mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 20:47:44 +00:00
51429 lines
1.6 MiB
51429 lines
1.6 MiB
/*
|
|
* Copyright 2013 Mozilla Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// This file is automatically generated
|
|
|
|
(function (global) {
|
|
if (global.DataView)
|
|
return;
|
|
if (!global.ArrayBuffer)
|
|
fail('ArrayBuffer not supported');
|
|
if (!Object.defineProperties)
|
|
fail('This module requires ECMAScript 5');
|
|
var nativele = new Int8Array(new Int32Array([
|
|
1
|
|
]).buffer)[0] === 1;
|
|
var temp = new Uint8Array(8);
|
|
global.DataView = function DataView(buffer, offset, length) {
|
|
if (!(buffer instanceof ArrayBuffer))
|
|
fail('Bad ArrayBuffer');
|
|
offset = offset || 0;
|
|
length = length || buffer.byteLength - offset;
|
|
if (offset < 0 || length < 0 || offset + length > buffer.byteLength)
|
|
fail('Illegal offset and/or length');
|
|
Object.defineProperties(this, {
|
|
buffer: {
|
|
value: buffer,
|
|
enumerable: false,
|
|
writable: false,
|
|
configurable: false
|
|
},
|
|
byteOffset: {
|
|
value: offset,
|
|
enumerable: false,
|
|
writable: false,
|
|
configurable: false
|
|
},
|
|
byteLength: {
|
|
value: length,
|
|
enumerable: false,
|
|
writable: false,
|
|
configurable: false
|
|
},
|
|
_bytes: {
|
|
value: new Uint8Array(buffer, offset, length),
|
|
enumerable: false,
|
|
writable: false,
|
|
configurable: false
|
|
}
|
|
});
|
|
};
|
|
global.DataView.prototype = {
|
|
constructor: DataView,
|
|
getInt8: function getInt8(offset) {
|
|
return get(this, Int8Array, 1, offset);
|
|
},
|
|
getUint8: function getUint8(offset) {
|
|
return get(this, Uint8Array, 1, offset);
|
|
},
|
|
getInt16: function getInt16(offset, le) {
|
|
return get(this, Int16Array, 2, offset, le);
|
|
},
|
|
getUint16: function getUint16(offset, le) {
|
|
return get(this, Uint16Array, 2, offset, le);
|
|
},
|
|
getInt32: function getInt32(offset, le) {
|
|
return get(this, Int32Array, 4, offset, le);
|
|
},
|
|
getUint32: function getUint32(offset, le) {
|
|
return get(this, Uint32Array, 4, offset, le);
|
|
},
|
|
getFloat32: function getFloat32(offset, le) {
|
|
return get(this, Float32Array, 4, offset, le);
|
|
},
|
|
getFloat64: function getFloat32(offset, le) {
|
|
return get(this, Float64Array, 8, offset, le);
|
|
},
|
|
setInt8: function setInt8(offset, value) {
|
|
set(this, Int8Array, 1, offset, value);
|
|
},
|
|
setUint8: function setUint8(offset, value) {
|
|
set(this, Uint8Array, 1, offset, value);
|
|
},
|
|
setInt16: function setInt16(offset, value, le) {
|
|
set(this, Int16Array, 2, offset, value, le);
|
|
},
|
|
setUint16: function setUint16(offset, value, le) {
|
|
set(this, Uint16Array, 2, offset, value, le);
|
|
},
|
|
setInt32: function setInt32(offset, value, le) {
|
|
set(this, Int32Array, 4, offset, value, le);
|
|
},
|
|
setUint32: function setUint32(offset, value, le) {
|
|
set(this, Uint32Array, 4, offset, value, le);
|
|
},
|
|
setFloat32: function setFloat32(offset, value, le) {
|
|
set(this, Float32Array, 4, offset, value, le);
|
|
},
|
|
setFloat64: function setFloat64(offset, value, le) {
|
|
set(this, Float64Array, 8, offset, value, le);
|
|
}
|
|
};
|
|
function get(view, type, size, offset, le) {
|
|
if (offset === undefined)
|
|
fail('Missing required offset argument');
|
|
if (offset < 0 || offset + size > view.byteLength)
|
|
fail('Invalid index: ' + offset);
|
|
if (size === 1 || !(!le) === nativele) {
|
|
if ((view.byteOffset + offset) % size === 0)
|
|
return new type(view.buffer, view.byteOffset + offset, 1)[0];
|
|
else {
|
|
for (var i = 0; i < size; i++)
|
|
temp[i] = view._bytes[offset + i];
|
|
return new type(temp.buffer)[0];
|
|
}
|
|
} else {
|
|
for (var i = 0; i < size; i++)
|
|
temp[size - i - 1] = view._bytes[offset + i];
|
|
return new type(temp.buffer)[0];
|
|
}
|
|
}
|
|
function set(view, type, size, offset, value, le) {
|
|
if (offset === undefined)
|
|
fail('Missing required offset argument');
|
|
if (value === undefined)
|
|
fail('Missing required value argument');
|
|
if (offset < 0 || offset + size > view.byteLength)
|
|
fail('Invalid index: ' + offset);
|
|
if (size === 1 || !(!le) === nativele) {
|
|
if ((view.byteOffset + offset) % size === 0) {
|
|
new type(view.buffer, view.byteOffset + offset, 1)[0] = value;
|
|
} else {
|
|
new type(temp.buffer)[0] = value;
|
|
for (var i = 0; i < size; i++)
|
|
view._bytes[i + offset] = temp[i];
|
|
}
|
|
} else {
|
|
new type(temp.buffer)[0] = value;
|
|
for (var i = 0; i < size; i++)
|
|
view._bytes[offset + i] = temp[size - 1 - i];
|
|
}
|
|
}
|
|
function fail(msg) {
|
|
throw new Error(msg);
|
|
}
|
|
}(this));
|
|
;
|
|
var ByteArray = ByteArray || function (undefined) {
|
|
ByteArrayClass.INITIAL_SIZE = 128;
|
|
ByteArrayClass.DEFAULT_OBJECT_ENCODING = 3;
|
|
function ByteArrayClass(bytes) {
|
|
if (bytes instanceof ByteArray) {
|
|
return bytes;
|
|
}
|
|
var initData = bytes || this.symbol && this.symbol.data;
|
|
if (initData) {
|
|
this.a = new ArrayBuffer(initData.length);
|
|
this.length = initData.length;
|
|
new Uint8Array(this.a).set(initData);
|
|
} else {
|
|
this.a = new ArrayBuffer(ByteArrayClass.INITIAL_SIZE);
|
|
this.length = 0;
|
|
}
|
|
this.position = 0;
|
|
this.cacheViews();
|
|
this.nativele = new Int8Array(new Int32Array([]).buffer)[0] === 1;
|
|
this.le = this.nativele;
|
|
this.objectEncoding = ByteArrayClass.DEFAULT_OBJECT_ENCODING;
|
|
this.bitBuffer = 0;
|
|
this.bitLength = 0;
|
|
}
|
|
;
|
|
function throwEOFError() {
|
|
runtime.throwErrorFromVM('flash.errors.EOFError', 'End of file was encountered.');
|
|
}
|
|
function throwRangeError() {
|
|
var error = Errors.ParamRangeError;
|
|
runtime.throwErrorFromVM('RangeError', getErrorMessage(error.code), error.code);
|
|
}
|
|
function throwCompressedDataError() {
|
|
var error = Errors.CompressedDataError;
|
|
runtime.throwErrorFromVM('CompressedDataError', getErrorMessage(error.code), error.code);
|
|
}
|
|
function checkRange(x, min, max) {
|
|
if (x !== clamp(x, min, max)) {
|
|
throwRangeError();
|
|
}
|
|
}
|
|
function get(b, m, size) {
|
|
if (b.position + size > b.length) {
|
|
throwEOFError();
|
|
}
|
|
var v = b.view[m](b.position, b.le);
|
|
b.position += size;
|
|
return v;
|
|
}
|
|
function set(b, m, size, v) {
|
|
var len = b.position + size;
|
|
b.ensureCapacity(len);
|
|
b.view[m](b.position, v, b.le);
|
|
b.position = len;
|
|
if (len > b.length) {
|
|
b.length = len;
|
|
}
|
|
}
|
|
var BAp = ByteArrayClass.prototype;
|
|
BAp.cacheViews = function cacheViews() {
|
|
var a = this.a;
|
|
this.int8v = new Int8Array(a);
|
|
this.uint8v = new Uint8Array(a);
|
|
this.view = new DataView(a);
|
|
};
|
|
BAp.getBytes = function getBytes() {
|
|
return new Uint8Array(this.a, 0, this.length);
|
|
};
|
|
BAp.ensureCapacity = function ensureCapacity(size) {
|
|
var origa = this.a;
|
|
if (origa.byteLength < size) {
|
|
var newSize = origa.byteLength;
|
|
while (newSize < size) {
|
|
newSize *= 2;
|
|
}
|
|
var copya = new ArrayBuffer(newSize);
|
|
var origv = this.int8v;
|
|
this.a = copya;
|
|
this.cacheViews();
|
|
this.int8v.set(origv);
|
|
}
|
|
};
|
|
BAp.clear = function clear() {
|
|
this.length = 0;
|
|
this.position = 0;
|
|
};
|
|
BAp.readBoolean = function readBoolean() {
|
|
if (this.position + 1 > this.length) {
|
|
throwEOFError();
|
|
}
|
|
return this.int8v[this.position++] !== 0;
|
|
};
|
|
BAp.readByte = function readByte() {
|
|
if (this.position + 1 > this.length) {
|
|
throwEOFError();
|
|
}
|
|
return this.int8v[this.position++];
|
|
};
|
|
BAp.readUnsignedByte = function readUnsignedByte() {
|
|
if (this.position + 1 > this.length) {
|
|
throwEOFError();
|
|
}
|
|
return this.uint8v[this.position++];
|
|
};
|
|
BAp.readBytes = function readBytes(bytes, offset, length) {
|
|
var pos = this.position;
|
|
if (!offset) {
|
|
offset = 0;
|
|
}
|
|
if (!length) {
|
|
length = this.length - pos;
|
|
}
|
|
if (pos + length > this.length) {
|
|
throwEOFError();
|
|
}
|
|
if (bytes.length < offset + length) {
|
|
bytes.ensureCapacity(offset + length);
|
|
bytes.length = offset + length;
|
|
}
|
|
bytes.int8v.set(new Int8Array(this.a, pos, length), offset);
|
|
this.position += length;
|
|
};
|
|
BAp.writeBoolean = function writeBoolean(v) {
|
|
var len = this.position + 1;
|
|
this.ensureCapacity(len);
|
|
this.int8v[this.position++] = v ? 1 : 0;
|
|
if (len > this.length) {
|
|
this.length = len;
|
|
}
|
|
};
|
|
BAp.writeByte = function writeByte(v) {
|
|
var len = this.position + 1;
|
|
this.ensureCapacity(len);
|
|
this.int8v[this.position++] = v;
|
|
if (len > this.length) {
|
|
this.length = len;
|
|
}
|
|
};
|
|
BAp.writeUnsignedByte = function writeUnsignedByte(v) {
|
|
var len = this.position + 1;
|
|
this.ensureCapacity(len);
|
|
this.uint8v[this.position++] = v;
|
|
if (len > this.length) {
|
|
this.length = len;
|
|
}
|
|
};
|
|
BAp.writeRawBytes = function writeRawBytes(bytes) {
|
|
var len = this.position + bytes.length;
|
|
this.ensureCapacity(len);
|
|
this.int8v.set(bytes, this.position);
|
|
this.position = len;
|
|
if (len > this.length) {
|
|
this.length = len;
|
|
}
|
|
};
|
|
BAp.readRawBytes = function readRawBytes() {
|
|
return new Int8Array(this.a, 0, this.length);
|
|
};
|
|
BAp.writeBytes = function writeBytes(bytes, offset, length) {
|
|
if (arguments.length < 2) {
|
|
offset = 0;
|
|
}
|
|
if (arguments.length < 3) {
|
|
length = 0;
|
|
}
|
|
checkRange(offset, 0, bytes.length);
|
|
checkRange(offset + length, 0, bytes.length);
|
|
if (length === 0) {
|
|
length = bytes.length - offset;
|
|
}
|
|
this.writeRawBytes(new Int8Array(bytes.a, offset, length));
|
|
};
|
|
BAp.readDouble = function readDouble() {
|
|
return get(this, 'getFloat64', 8);
|
|
};
|
|
BAp.readFloat = function readFloat() {
|
|
return get(this, 'getFloat32', 4);
|
|
};
|
|
BAp.readInt = function readInt() {
|
|
return get(this, 'getInt32', 4);
|
|
};
|
|
BAp.readShort = function readShort() {
|
|
return get(this, 'getInt16', 2);
|
|
};
|
|
BAp.readUnsignedInt = function readUnsignedInt() {
|
|
return get(this, 'getUint32', 4);
|
|
};
|
|
BAp.readUnsignedShort = function readUnsignedShort() {
|
|
return get(this, 'getUint16', 2);
|
|
};
|
|
BAp.writeDouble = function writeDouble(v) {
|
|
set(this, 'setFloat64', 8, v);
|
|
};
|
|
BAp.writeFloat = function writeFloat(v) {
|
|
set(this, 'setFloat32', 4, v);
|
|
};
|
|
BAp.writeInt = function writeInt(v) {
|
|
set(this, 'setInt32', 4, v);
|
|
};
|
|
BAp.writeShort = function writeShort(v) {
|
|
set(this, 'setInt16', 2, v);
|
|
};
|
|
BAp.writeUnsignedInt = function writeUnsignedInt(v) {
|
|
set(this, 'setUint32', 4, v);
|
|
};
|
|
BAp.writeUnsignedShort = function writeUnsignedShort(v) {
|
|
set(this, 'setUint16', 2, v);
|
|
};
|
|
var codeLengthOrder = [
|
|
16,
|
|
17,
|
|
18,
|
|
0,
|
|
8,
|
|
7,
|
|
9,
|
|
6,
|
|
10,
|
|
5,
|
|
11,
|
|
4,
|
|
12,
|
|
3,
|
|
13,
|
|
2,
|
|
14,
|
|
1,
|
|
15
|
|
];
|
|
var distanceCodes = [];
|
|
var distanceExtraBits = [];
|
|
for (var i = 0, j = 0, code = 1; i < 30; ++i) {
|
|
distanceCodes[i] = code;
|
|
code += 1 << (distanceExtraBits[i] = ~(~((j += i > 2 ? 1 : 0) / 2)));
|
|
}
|
|
var bitLengths = [];
|
|
for (var i = 0; i < 32; ++i) {
|
|
bitLengths[i] = 5;
|
|
}
|
|
var fixedDistanceTable = makeHuffmanTable(bitLengths);
|
|
var lengthCodes = [];
|
|
var lengthExtraBits = [];
|
|
for (var i = 0, j = 0, code = 3; i < 29; ++i) {
|
|
lengthCodes[i] = code - (i == 28 ? 1 : 0);
|
|
code += 1 << (lengthExtraBits[i] = ~(~((j += i > 4 ? 1 : 0) / 4 % 6)));
|
|
}
|
|
for (var i = 0; i < 288; ++i) {
|
|
bitLengths[i] = i < 144 || i > 279 ? 8 : i < 256 ? 9 : 7;
|
|
}
|
|
var fixedLiteralTable = makeHuffmanTable(bitLengths);
|
|
function makeHuffmanTable(bitLengths) {
|
|
var maxBits = Math.max.apply(null, bitLengths);
|
|
var numLengths = bitLengths.length;
|
|
var size = 1 << maxBits;
|
|
var codes = new Uint32Array(size);
|
|
for (var code = 0, len = 1, skip = 2; len <= maxBits; code <<= 1, ++len, skip <<= 1) {
|
|
for (var val = 0; val < numLengths; ++val) {
|
|
if (bitLengths[val] === len) {
|
|
var lsb = 0;
|
|
for (var i = 0; i < len; ++i) {
|
|
lsb = lsb * 2 + (code >> i & 1);
|
|
}
|
|
for (var i = lsb; i < size; i += skip) {
|
|
codes[i] = len << 16 | val;
|
|
}
|
|
++code;
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
codes: codes,
|
|
maxBits: maxBits
|
|
};
|
|
}
|
|
function inflateBlock(input, output) {
|
|
var header = readBits(input, 3);
|
|
switch (header >> 1) {
|
|
case 0:
|
|
input.bitBuffer = input.bitLength = 0;
|
|
var len = input.readUnsignedShort();
|
|
var nlen = input.readUnsignedShort();
|
|
if ((~nlen & 65535) !== len) {
|
|
throwCompressedDataError();
|
|
}
|
|
output.writeBytes(input, input.position, len);
|
|
input.position += len;
|
|
break;
|
|
case 1:
|
|
inflate(input, output, fixedLiteralTable, fixedDistanceTable);
|
|
break;
|
|
case 2:
|
|
var bitLengths = [];
|
|
var numLiteralCodes = readBits(input, 5) + 257;
|
|
var numDistanceCodes = readBits(input, 5) + 1;
|
|
var numCodes = numLiteralCodes + numDistanceCodes;
|
|
var numLengthCodes = readBits(input, 4) + 4;
|
|
for (var i = 0; i < 19; ++i) {
|
|
bitLengths[codeLengthOrder[i]] = i < numLengthCodes ? readBits(input, 3) : 0;
|
|
}
|
|
var codeLengthTable = makeHuffmanTable(bitLengths);
|
|
bitLengths = [];
|
|
var i = 0;
|
|
var prev = 0;
|
|
while (i < numCodes) {
|
|
var j = 1;
|
|
var sym = readCode(input, codeLengthTable);
|
|
switch (sym) {
|
|
case 16:
|
|
j = readBits(input, 2) + 3;
|
|
sym = prev;
|
|
break;
|
|
case 17:
|
|
j = readBits(input, 3) + 3;
|
|
sym = 0;
|
|
break;
|
|
case 18:
|
|
j = readBits(input, 7) + 11;
|
|
sym = 0;
|
|
break;
|
|
default:
|
|
prev = sym;
|
|
}
|
|
while (j--) {
|
|
bitLengths[i++] = sym;
|
|
}
|
|
}
|
|
var distanceTable = makeHuffmanTable(bitLengths.splice(numLiteralCodes, numDistanceCodes));
|
|
var literalTable = makeHuffmanTable(bitLengths);
|
|
inflate(input, output, literalTable, distanceTable);
|
|
break;
|
|
default:
|
|
fail('unknown block type', 'inflate');
|
|
}
|
|
}
|
|
function readBits(input, size) {
|
|
var buffer = input.bitBuffer;
|
|
var bufflen = input.bitLength;
|
|
while (size > bufflen) {
|
|
buffer |= input.readUnsignedByte() << bufflen;
|
|
bufflen += 8;
|
|
}
|
|
input.bitBuffer = buffer >>> size;
|
|
input.bitLength = bufflen - size;
|
|
return buffer & (1 << size) - 1;
|
|
}
|
|
function inflate(input, output, literalTable, distanceTable) {
|
|
var sym;
|
|
while ((sym = readCode(input, literalTable)) !== 256) {
|
|
if (sym < 256) {
|
|
output.writeUnsignedByte(sym);
|
|
} else {
|
|
sym -= 257;
|
|
var len = lengthCodes[sym] + readBits(input, lengthExtraBits[sym]);
|
|
sym = readCode(input, distanceTable);
|
|
var distance = distanceCodes[sym] + readBits(input, distanceExtraBits[sym]);
|
|
output.writeBytes(output, output.position - distance, len);
|
|
}
|
|
}
|
|
}
|
|
function readCode(input, codeTable) {
|
|
var buffer = input.bitBuffer;
|
|
var bitlen = input.bitLength;
|
|
var maxBits = codeTable.maxBits;
|
|
while (maxBits > bitlen) {
|
|
buffer |= input.readUnsignedByte() << bitlen;
|
|
bitlen += 8;
|
|
}
|
|
var code = codeTable.codes[buffer & (1 << maxBits) - 1];
|
|
var len = code >> 16;
|
|
if (!len) {
|
|
throwCompressedDataError();
|
|
}
|
|
input.bitBuffer = buffer >>> len;
|
|
input.bitLength = bitlen - len;
|
|
return code & 65535;
|
|
}
|
|
function adler32(data, start, end) {
|
|
var a = 1;
|
|
var b = 0;
|
|
for (var i = start; i < end; ++i) {
|
|
a = (a + (data[i] & 255)) % 65521;
|
|
b = (b + a) % 65521;
|
|
}
|
|
return b << 16 | a;
|
|
}
|
|
BAp.compress = function (algorithm) {
|
|
this.position = 0;
|
|
var output = new ByteArray();
|
|
switch (algorithm) {
|
|
case 'zlib':
|
|
output.writeUnsignedByte(120);
|
|
output.writeUnsignedByte(156);
|
|
case 'deflate':
|
|
output.le = true;
|
|
var len = this.length;
|
|
output.ensureCapacity(len + Math.ceil(len / 65535) * 5 + 4);
|
|
while (len > 65535) {
|
|
output.writeUnsignedByte(0);
|
|
output.writeUnsignedShort(65535);
|
|
output.writeUnsignedShort(0);
|
|
output.writeBytes(this, this.position, 65535);
|
|
this.position += 65535;
|
|
len -= 65535;
|
|
}
|
|
output.writeUnsignedByte(0);
|
|
output.writeUnsignedShort(len);
|
|
output.writeUnsignedShort(~len & 65535);
|
|
output.writeBytes(this, this.position, len);
|
|
if (algorithm === 'zlib') {
|
|
output.writeUnsignedInt(adler32(this.uint8v, 0, this.length));
|
|
}
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
this.ensureCapacity(output.uint8v.length);
|
|
this.uint8v.set(output.uint8v);
|
|
this.length = output.length;
|
|
this.position = 0;
|
|
};
|
|
BAp.uncompress = function (algorithm) {
|
|
var output = new ByteArray();
|
|
switch (algorithm) {
|
|
case 'zlib':
|
|
var header = this.readUnsignedShort();
|
|
if ((header & 3840) !== 2048 || header % 31 !== 0 || header & 32) {
|
|
throwCompressedDataError();
|
|
}
|
|
case 'deflate':
|
|
var le = this.le;
|
|
this.le = true;
|
|
while (this.position < this.length - 6) {
|
|
inflateBlock(this, output);
|
|
}
|
|
this.le = le;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
this.ensureCapacity(output.uint8v.length);
|
|
this.uint8v.set(output.uint8v);
|
|
this.length = output.length;
|
|
this.position = 0;
|
|
};
|
|
return ByteArrayClass;
|
|
}();
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (Options) {
|
|
var Argument = function () {
|
|
function Argument(shortName, longName, type, options) {
|
|
this.shortName = shortName;
|
|
this.longName = longName;
|
|
this.type = type;
|
|
options = options || {};
|
|
this.positional = options.positional;
|
|
this.parseFn = options.parse;
|
|
this.value = options.defaultValue;
|
|
}
|
|
Argument.prototype.parse = function (value) {
|
|
if (this.type === 'boolean') {
|
|
true;
|
|
this.value = value;
|
|
} else if (this.type === 'number') {
|
|
true;
|
|
this.value = parseInt(value, 10);
|
|
} else {
|
|
this.value = value;
|
|
}
|
|
if (this.parseFn) {
|
|
this.parseFn(this.value);
|
|
}
|
|
};
|
|
return Argument;
|
|
}();
|
|
Options.Argument = Argument;
|
|
var ArgumentParser = function () {
|
|
function ArgumentParser() {
|
|
this.args = [];
|
|
}
|
|
ArgumentParser.prototype.addArgument = function (shortName, longName, type, options) {
|
|
var argument = new Argument(shortName, longName, type, options);
|
|
this.args.push(argument);
|
|
return argument;
|
|
};
|
|
ArgumentParser.prototype.addBoundOption = function (option) {
|
|
var options = {
|
|
parse: function (x) {
|
|
option.value = x;
|
|
}
|
|
};
|
|
this.args.push(new Argument(option.shortName, option.longName, option.type, options));
|
|
};
|
|
ArgumentParser.prototype.addBoundOptionSet = function (optionSet) {
|
|
var self = this;
|
|
optionSet.options.forEach(function (x) {
|
|
if (x instanceof OptionSet) {
|
|
self.addBoundOptionSet(x);
|
|
} else {
|
|
true;
|
|
self.addBoundOption(x);
|
|
}
|
|
});
|
|
};
|
|
ArgumentParser.prototype.getUsage = function () {
|
|
var str = '';
|
|
this.args.forEach(function (x) {
|
|
if (!x.positional) {
|
|
str += '[-' + x.shortName + '|--' + x.longName + (x.type === 'boolean' ? '' : ' ' + x.type[0].toUpperCase()) + ']';
|
|
} else {
|
|
str += x.longName;
|
|
}
|
|
str += ' ';
|
|
});
|
|
return str;
|
|
};
|
|
ArgumentParser.prototype.parse = function (args) {
|
|
var nonPositionalArgumentMap = {};
|
|
var positionalArgumentList = [];
|
|
this.args.forEach(function (x) {
|
|
if (x.positional) {
|
|
positionalArgumentList.push(x);
|
|
} else {
|
|
nonPositionalArgumentMap['-' + x.shortName] = x;
|
|
nonPositionalArgumentMap['--' + x.longName] = x;
|
|
}
|
|
});
|
|
var leftoverArguments = [];
|
|
while (args.length) {
|
|
var argString = args.shift();
|
|
var argument = null, value = argString;
|
|
if (argString == '--') {
|
|
leftoverArguments = leftoverArguments.concat(args);
|
|
break;
|
|
} else if (argString.slice(0, 1) == '-' || argString.slice(0, 2) == '--') {
|
|
argument = nonPositionalArgumentMap[argString];
|
|
true;
|
|
if (!argument) {
|
|
continue;
|
|
}
|
|
if (argument.type !== 'boolean') {
|
|
value = args.shift();
|
|
true;
|
|
} else {
|
|
value = true;
|
|
}
|
|
} else if (positionalArgumentList.length) {
|
|
argument = positionalArgumentList.shift();
|
|
} else {
|
|
leftoverArguments.push(value);
|
|
}
|
|
if (argument) {
|
|
argument.parse(value);
|
|
}
|
|
}
|
|
true;
|
|
return leftoverArguments;
|
|
};
|
|
return ArgumentParser;
|
|
}();
|
|
Options.ArgumentParser = ArgumentParser;
|
|
var OptionSet = function () {
|
|
function OptionSet(name) {
|
|
this.name = name;
|
|
this.options = [];
|
|
}
|
|
OptionSet.prototype.register = function (option) {
|
|
this.options.push(option);
|
|
return option;
|
|
};
|
|
OptionSet.prototype.trace = function (writer) {
|
|
writer.enter(this.name + ' {');
|
|
this.options.forEach(function (option) {
|
|
option.trace(writer);
|
|
});
|
|
writer.leave('}');
|
|
};
|
|
return OptionSet;
|
|
}();
|
|
Options.OptionSet = OptionSet;
|
|
var Option = function () {
|
|
function Option(shortName, longName, type, defaultValue, description) {
|
|
this.longName = longName;
|
|
this.shortName = shortName;
|
|
this.type = type;
|
|
this.defaultValue = defaultValue;
|
|
this.value = defaultValue;
|
|
this.description = description;
|
|
}
|
|
Option.prototype.parse = function (value) {
|
|
this.value = value;
|
|
};
|
|
Option.prototype.trace = function (writer) {
|
|
writer.writeLn(('-' + this.shortName + '|--' + this.longName).padRight(' ', 30) + ' = ' + this.type + ' ' + this.value + ' [' + this.defaultValue + ']' + ' (' + this.description + ')');
|
|
};
|
|
return Option;
|
|
}();
|
|
Options.Option = Option;
|
|
}(Shumway.Options || (Shumway.Options = {})));
|
|
var Options = Shumway.Options;
|
|
}(Shumway || (Shumway = {})));
|
|
if (typeof exports !== 'undefined') {
|
|
exports['Shumway'] = Shumway;
|
|
}
|
|
var ArgumentParser = Shumway.Options.ArgumentParser;
|
|
var Option = Shumway.Options.Option;
|
|
var OptionSet = Shumway.Options.OptionSet;
|
|
var Option = Shumway.Options.Option;
|
|
var OptionSet = Shumway.Options.OptionSet;
|
|
var coreOptions = new OptionSet('Core Options');
|
|
var Timeline = function () {
|
|
var barColor = 'rgba(255,255,255, 0.075)';
|
|
var backgroundColor = 'rgb(61, 61, 61)';
|
|
var backgroundColorInfo = 'rgba(0,0,0, 0.85)';
|
|
var fpsLineColor = 'rgb(255,64,0)';
|
|
var textColor = '#ccc';
|
|
function timeline(canvas) {
|
|
this.depth = 0;
|
|
this.start = 0;
|
|
this.index = 0;
|
|
this.marks = new Shumway.CircularBuffer(Int32Array);
|
|
this.times = new Shumway.CircularBuffer(Float64Array);
|
|
this.frameRate = 12;
|
|
this.maxFrameTime = 1000 * 2 / this.frameRate;
|
|
this.refreshFrequency = 10;
|
|
this.refreshCounter = 0;
|
|
this.count = 0;
|
|
this.kinds = createEmptyObject();
|
|
this.kindCount = 0;
|
|
this.canvas = canvas;
|
|
this.context = canvas.getContext('2d', {
|
|
original: true
|
|
});
|
|
this.fillStyles = [
|
|
'rgb(85, 152, 213)',
|
|
'#bfd8a7',
|
|
'#d906d7'
|
|
];
|
|
window.addEventListener('resize', this.resizeHandler.bind(this), false);
|
|
this.resizeHandler();
|
|
}
|
|
timeline.prototype.setFrameRate = function setFrameRate(frameRate) {
|
|
this.frameRate = frameRate;
|
|
this.maxFrameTime = 1000 * 2 / frameRate;
|
|
};
|
|
timeline.prototype.refreshEvery = function refreshEvery(freq) {
|
|
this.refreshFrequency = freq;
|
|
this.refreshCounter = 0;
|
|
};
|
|
var ENTER = 3203334144 | 0;
|
|
var LEAVE = 3735879680 | 0;
|
|
timeline.prototype.registerKind = function getKind(name, fillStyle) {
|
|
if (this.kinds[name] === undefined) {
|
|
this.fillStyles[this.kindCount] = fillStyle;
|
|
this.kinds[name] = this.kindCount++;
|
|
} else {
|
|
this.fillStyles[this.kinds[name]] = fillStyle;
|
|
}
|
|
};
|
|
timeline.prototype.getKind = function getKind(name) {
|
|
if (this.kinds[name] === undefined) {
|
|
this.kinds[name] = this.kindCount++;
|
|
if (this.kindCount > this.fillStyles.length) {
|
|
this.fillStyles.push(randomStyle());
|
|
}
|
|
}
|
|
return this.kinds[name];
|
|
};
|
|
timeline.prototype.enter = function enter(name) {
|
|
this.depth++;
|
|
this.marks.write(ENTER | this.getKind(name));
|
|
this.times.write(performance.now());
|
|
};
|
|
timeline.prototype.leave = function leave(name) {
|
|
this.marks.write(LEAVE | this.getKind(name));
|
|
this.times.write(performance.now());
|
|
this.depth--;
|
|
if (this.depth === 0) {
|
|
this.count++;
|
|
if (++this.refreshCounter == this.refreshFrequency) {
|
|
this.refreshCounter = 0;
|
|
this.paint();
|
|
}
|
|
}
|
|
};
|
|
timeline.prototype.gatherFrames = function gatherFrames(maxFrames) {
|
|
var stack = [];
|
|
var frames = [];
|
|
var times = this.times;
|
|
maxFrames++;
|
|
this.marks.forEachInReverse(function (mark, i) {
|
|
var time = times.get(i);
|
|
if ((mark & 4294901760) === ENTER) {
|
|
var node = stack.pop();
|
|
node.startTime = time;
|
|
if (!stack.length) {
|
|
if (frames.length && !frames[0].total) {
|
|
frames[0].total = frames[0].startTime - time;
|
|
}
|
|
frames.unshift(node);
|
|
} else {
|
|
var top = stack.top();
|
|
if (!top.children) {
|
|
top.children = [
|
|
node
|
|
];
|
|
} else {
|
|
top.children.push(node);
|
|
}
|
|
}
|
|
} else if ((mark & 4294901760) === LEAVE) {
|
|
if (frames.length > maxFrames) {
|
|
return true;
|
|
}
|
|
stack.push({
|
|
kind: mark & 65535,
|
|
endTime: time
|
|
});
|
|
}
|
|
});
|
|
return frames;
|
|
};
|
|
timeline.prototype.resizeHandler = function resizeHandler(event) {
|
|
var parent = this.canvas.parentElement;
|
|
this.cw = parent.offsetWidth;
|
|
this.ch = parent.offsetHeight - 1;
|
|
var devicePixelRatio = window.devicePixelRatio || 1;
|
|
var backingStoreRatio = this.context.webkitBackingStorePixelRatio || this.context.mozBackingStorePixelRatio || this.context.msBackingStorePixelRatio || this.context.oBackingStorePixelRatio || this.context.backingStorePixelRatio || 1;
|
|
if (devicePixelRatio !== backingStoreRatio) {
|
|
var ratio = devicePixelRatio / backingStoreRatio;
|
|
this.canvas.width = this.cw * ratio;
|
|
this.canvas.height = this.ch * ratio;
|
|
this.canvas.style.width = this.cw + 'px';
|
|
this.canvas.style.height = this.ch + 'px';
|
|
this.context.scale(ratio, ratio);
|
|
} else {
|
|
this.canvas.width = this.cw;
|
|
this.canvas.height = this.ch;
|
|
}
|
|
this.context.font = '10px Consolas, "Liberation Mono", Courier, monospace';
|
|
};
|
|
timeline.prototype.paint = function paint() {
|
|
var w = 10;
|
|
var gap = 1;
|
|
var maxFrames = this.cw / (w + gap) | 0;
|
|
var frames = this.gatherFrames(maxFrames);
|
|
var context = this.context;
|
|
var maxFrameTime = this.maxFrameTime;
|
|
var fillStyles = this.fillStyles;
|
|
context.clearRect(0, 0, this.cw, this.ch);
|
|
var maxFrameRate = 0;
|
|
var maxFrameRateCount = 0;
|
|
var avgFrameRate = 0;
|
|
var avgFrameRateCount = 0;
|
|
var offsetW;
|
|
context.save();
|
|
context.translate(0, this.ch);
|
|
context.scale(1, -this.ch / maxFrameTime);
|
|
for (var i = 0; i < frames.length - 1; i++) {
|
|
var frame = frames[i];
|
|
maxFrameRate += frame.endTime - frame.startTime;
|
|
maxFrameRateCount++;
|
|
if (frame.total) {
|
|
avgFrameRate += frame.total;
|
|
avgFrameRateCount++;
|
|
}
|
|
offsetW = i * (w + gap);
|
|
context.fillStyle = barColor;
|
|
context.fillRect(offsetW, 0, w, frames[i + 1].startTime - frame.startTime);
|
|
drawNode(frame, frame.startTime);
|
|
}
|
|
function drawNode(node, frameStartTime) {
|
|
var nodeTime = node.endTime - node.startTime;
|
|
var offsetH = node.startTime - frameStartTime;
|
|
context.fillStyle = fillStyles[node.kind];
|
|
context.fillRect(offsetW, offsetH, w, nodeTime);
|
|
if (node.children) {
|
|
var children = node.children;
|
|
for (var i = 0, n = children.length; i < n; i++) {
|
|
drawNode(children[i], frameStartTime);
|
|
}
|
|
}
|
|
}
|
|
var lineH = 1000 / this.frameRate;
|
|
context.beginPath();
|
|
context.lineWidth = 0.5;
|
|
context.moveTo(0, lineH);
|
|
context.lineTo(this.cw, lineH);
|
|
context.strokeStyle = fpsLineColor;
|
|
context.stroke();
|
|
context.restore();
|
|
context.fillStyle = backgroundColorInfo;
|
|
context.fillRect(0, 0, this.cw, 20);
|
|
var textOffset;
|
|
var sFrameCount = this.count;
|
|
var sMaxFrameRate = Math.round(1000 * maxFrameRateCount / maxFrameRate);
|
|
var sAvgFrameRate = Math.round(1000 * avgFrameRateCount / avgFrameRate);
|
|
var space = 5;
|
|
textOffset = 5;
|
|
context.fillStyle = textColor;
|
|
context.fillText(sFrameCount, textOffset, 13);
|
|
textOffset += context.measureText(sFrameCount).width + space;
|
|
context.fillText(sMaxFrameRate, textOffset, 13);
|
|
textOffset += context.measureText(sMaxFrameRate).width + space;
|
|
context.fillText(sAvgFrameRate, textOffset, 13);
|
|
var basicOffset = textOffset + context.measureText(sAvgFrameRate).width + space;
|
|
textOffset = this.cw;
|
|
for (var k in this.kinds) {
|
|
context.fillStyle = this.fillStyles[this.getKind(k)];
|
|
textOffset -= context.measureText(k).width + space;
|
|
if (textOffset > basicOffset) {
|
|
this.context.fillText(k, textOffset, 13);
|
|
}
|
|
}
|
|
};
|
|
return timeline;
|
|
}();
|
|
var create = Object.create;
|
|
var defineProperty = Object.defineProperty;
|
|
var keys = Object.keys;
|
|
var isArray = Array.isArray;
|
|
var fromCharCode = String.fromCharCode;
|
|
var logE = Math.log;
|
|
var max = Math.max;
|
|
var min = Math.min;
|
|
var pow = Math.pow;
|
|
var push = Array.prototype.push;
|
|
var slice = Array.prototype.slice;
|
|
var splice = Array.prototype.splice;
|
|
function fail(msg, context) {
|
|
throw new Error((context ? context + ': ' : '') + msg);
|
|
}
|
|
function assert(cond, msg, context) {
|
|
if (!cond)
|
|
fail(msg, context);
|
|
}
|
|
function scriptProperties(namespace, props) {
|
|
return props.reduce(function (o, p) {
|
|
o[p] = namespace + ' ' + p;
|
|
return o;
|
|
}, {});
|
|
}
|
|
function cloneObject(obj) {
|
|
var clone = Object.create(null);
|
|
for (var prop in obj)
|
|
clone[prop] = obj[prop];
|
|
return clone;
|
|
}
|
|
function sortNumeric(a, b) {
|
|
return a - b;
|
|
}
|
|
function sortByZindex(a, b) {
|
|
return a._zindex - b._zindex;
|
|
}
|
|
function rgbaObjToStr(color) {
|
|
return 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')';
|
|
}
|
|
function rgbIntAlphaToStr(color, alpha) {
|
|
color |= 0;
|
|
if (alpha >= 1) {
|
|
var colorStr = color.toString(16);
|
|
while (colorStr.length < 6) {
|
|
colorStr = '0' + colorStr;
|
|
}
|
|
return '#' + colorStr;
|
|
}
|
|
var red = color >> 16 & 255;
|
|
var green = color >> 8 & 255;
|
|
var blue = color & 255;
|
|
return 'rgba(' + red + ',' + green + ',' + blue + ',' + alpha + ')';
|
|
}
|
|
function argbUintToStr(argb) {
|
|
return 'rgba(' + (argb >>> 16 & 255) + ',' + (argb >>> 8 & 255) + ',' + (argb & 255) + ',' + (argb >>> 24 & 255) / 255 + ')';
|
|
}
|
|
(function functionNameSupport() {
|
|
if (eval('function t() {} t.name === \'t\'')) {
|
|
return;
|
|
}
|
|
Object.defineProperty(Function.prototype, 'name', {
|
|
get: function () {
|
|
if (this.__name) {
|
|
return this.__name;
|
|
}
|
|
var m = /function\s([^\(]+)/.exec(this.toString());
|
|
var name = m && m[1] !== 'anonymous' ? m[1] : null;
|
|
this.__name = name;
|
|
return name;
|
|
},
|
|
configurable: true,
|
|
enumerable: false
|
|
});
|
|
}());
|
|
var randomStyleCache;
|
|
var nextStyle = 0;
|
|
function randomStyle() {
|
|
if (!randomStyleCache) {
|
|
randomStyleCache = [
|
|
'#ff5e3a',
|
|
'#ff9500',
|
|
'#ffdb4c',
|
|
'#87fc70',
|
|
'#52edc7',
|
|
'#1ad6fd',
|
|
'#c644fc',
|
|
'#ef4db6',
|
|
'#4a4a4a',
|
|
'#dbddde',
|
|
'#ff3b30',
|
|
'#ff9500',
|
|
'#ffcc00',
|
|
'#4cd964',
|
|
'#34aadc',
|
|
'#007aff',
|
|
'#5856d6',
|
|
'#ff2d55',
|
|
'#8e8e93',
|
|
'#c7c7cc',
|
|
'#5ad427',
|
|
'#c86edf',
|
|
'#d1eefc',
|
|
'#e0f8d8',
|
|
'#fb2b69',
|
|
'#f7f7f7',
|
|
'#1d77ef',
|
|
'#d6cec3',
|
|
'#55efcb',
|
|
'#ff4981',
|
|
'#ffd3e0',
|
|
'#f7f7f7',
|
|
'#ff1300',
|
|
'#1f1f21',
|
|
'#bdbec2',
|
|
'#ff3a2d'
|
|
];
|
|
}
|
|
return randomStyleCache[nextStyle++ % randomStyleCache.length];
|
|
}
|
|
(function PromiseClosure() {
|
|
var global = Function('return this')();
|
|
if (global.Promise) {
|
|
if (typeof global.Promise.all !== 'function') {
|
|
global.Promise.all = function (iterable) {
|
|
var count = 0, results = [], resolve, reject;
|
|
var promise = new global.Promise(function (resolve_, reject_) {
|
|
resolve = resolve_;
|
|
reject = reject_;
|
|
});
|
|
iterable.forEach(function (p, i) {
|
|
count++;
|
|
p.then(function (result) {
|
|
results[i] = result;
|
|
count--;
|
|
if (count === 0) {
|
|
resolve(results);
|
|
}
|
|
}, reject);
|
|
});
|
|
if (count === 0) {
|
|
resolve(results);
|
|
}
|
|
return promise;
|
|
};
|
|
}
|
|
if (typeof global.Promise.resolve !== 'function') {
|
|
global.Promise.resolve = function (x) {
|
|
return new global.Promise(function (resolve) {
|
|
resolve(x);
|
|
});
|
|
};
|
|
}
|
|
return;
|
|
}
|
|
function getDeferred(C) {
|
|
if (typeof C !== 'function') {
|
|
throw new TypeError('Invalid deferred constructor');
|
|
}
|
|
var resolver = createDeferredConstructionFunctions();
|
|
var promise = new C(resolver);
|
|
var resolve = resolver.resolve;
|
|
if (typeof resolve !== 'function') {
|
|
throw new TypeError('Invalid resolve construction function');
|
|
}
|
|
var reject = resolver.reject;
|
|
if (typeof reject !== 'function') {
|
|
throw new TypeError('Invalid reject construction function');
|
|
}
|
|
return {
|
|
promise: promise,
|
|
resolve: resolve,
|
|
reject: reject
|
|
};
|
|
}
|
|
function updateDeferredFromPotentialThenable(x, deferred) {
|
|
if (typeof x !== 'object' || x === null) {
|
|
return false;
|
|
}
|
|
try {
|
|
var then = x.then;
|
|
if (typeof then !== 'function') {
|
|
return false;
|
|
}
|
|
var thenCallResult = then.call(x, deferred.resolve, deferred.reject);
|
|
} catch (e) {
|
|
var reject = deferred.reject;
|
|
reject(e);
|
|
}
|
|
return true;
|
|
}
|
|
function isPromise(x) {
|
|
return typeof x === 'object' && x !== null && typeof x.promiseStatus !== 'undefined';
|
|
}
|
|
function rejectPromise(promise, reason) {
|
|
if (promise.promiseStatus !== 'unresolved') {
|
|
return;
|
|
}
|
|
var reactions = promise.rejectReactions;
|
|
promise.result = reason;
|
|
promise.resolveReactions = undefined;
|
|
promise.rejectReactions = undefined;
|
|
promise.promiseStatus = 'has-rejection';
|
|
triggerPromiseReactions(reactions, reason);
|
|
}
|
|
function resolvePromise(promise, resolution) {
|
|
if (promise.promiseStatus !== 'unresolved') {
|
|
return;
|
|
}
|
|
var reactions = promise.resolveReactions;
|
|
promise.result = resolution;
|
|
promise.resolveReactions = undefined;
|
|
promise.rejectReactions = undefined;
|
|
promise.promiseStatus = 'has-resolution';
|
|
triggerPromiseReactions(reactions, resolution);
|
|
}
|
|
function triggerPromiseReactions(reactions, argument) {
|
|
for (var i = 0; i < reactions.length; i++) {
|
|
queueMicrotask({
|
|
reaction: reactions[i],
|
|
argument: argument
|
|
});
|
|
}
|
|
}
|
|
function queueMicrotask(task) {
|
|
if (microtasksQueue.length === 0) {
|
|
setTimeout(handleMicrotasksQueue, 0);
|
|
}
|
|
microtasksQueue.push(task);
|
|
}
|
|
function executePromiseReaction(reaction, argument) {
|
|
var deferred = reaction.deferred;
|
|
var handler = reaction.handler;
|
|
var handlerResult, updateResult;
|
|
try {
|
|
handlerResult = handler(argument);
|
|
} catch (e) {
|
|
var reject = deferred.reject;
|
|
return reject(e);
|
|
}
|
|
if (handlerResult === deferred.promise) {
|
|
var reject = deferred.reject;
|
|
return reject(new TypeError('Self resolution'));
|
|
}
|
|
try {
|
|
updateResult = updateDeferredFromPotentialThenable(handlerResult, deferred);
|
|
if (!updateResult) {
|
|
var resolve = deferred.resolve;
|
|
return resolve(handlerResult);
|
|
}
|
|
} catch (e) {
|
|
var reject = deferred.reject;
|
|
return reject(e);
|
|
}
|
|
}
|
|
var microtasksQueue = [];
|
|
function handleMicrotasksQueue() {
|
|
while (microtasksQueue.length > 0) {
|
|
var task = microtasksQueue[0];
|
|
try {
|
|
executePromiseReaction(task.reaction, task.argument);
|
|
} catch (e) {
|
|
if (typeof Promise.onerror === 'function') {
|
|
Promise.onerror(e);
|
|
}
|
|
}
|
|
microtasksQueue.shift();
|
|
}
|
|
}
|
|
function throwerFunction(e) {
|
|
throw e;
|
|
}
|
|
function identityFunction(x) {
|
|
return x;
|
|
}
|
|
function createRejectPromiseFunction(promise) {
|
|
return function (reason) {
|
|
rejectPromise(promise, reason);
|
|
};
|
|
}
|
|
function createResolvePromiseFunction(promise) {
|
|
return function (resolution) {
|
|
resolvePromise(promise, resolution);
|
|
};
|
|
}
|
|
function createDeferredConstructionFunctions() {
|
|
var fn = function (resolve, reject) {
|
|
fn.resolve = resolve;
|
|
fn.reject = reject;
|
|
};
|
|
return fn;
|
|
}
|
|
function createPromiseResolutionHandlerFunctions(promise, fulfillmentHandler, rejectionHandler) {
|
|
return function (x) {
|
|
if (x === promise) {
|
|
return rejectionHandler(new TypeError('Self resolution'));
|
|
}
|
|
var cstr = promise.promiseConstructor;
|
|
if (isPromise(x)) {
|
|
var xConstructor = x.promiseConstructor;
|
|
if (xConstructor === cstr) {
|
|
return x.then(fulfillmentHandler, rejectionHandler);
|
|
}
|
|
}
|
|
var deferred = getDeferred(cstr);
|
|
var updateResult = updateDeferredFromPotentialThenable(x, deferred);
|
|
if (updateResult) {
|
|
var deferredPromise = deferred.promise;
|
|
return deferredPromise.then(fulfillmentHandler, rejectionHandler);
|
|
}
|
|
return fulfillmentHandler(x);
|
|
};
|
|
}
|
|
function createPromiseAllCountdownFunction(index, values, deferred, countdownHolder) {
|
|
return function (x) {
|
|
values[index] = x;
|
|
countdownHolder.countdown--;
|
|
if (countdownHolder.countdown === 0) {
|
|
deferred.resolve(values);
|
|
}
|
|
};
|
|
}
|
|
function Promise(resolver) {
|
|
if (typeof resolver !== 'function') {
|
|
throw new TypeError('resolver is not a function');
|
|
}
|
|
var promise = this;
|
|
if (typeof promise !== 'object') {
|
|
throw new TypeError('Promise to initialize is not an object');
|
|
}
|
|
promise.promiseStatus = 'unresolved';
|
|
promise.resolveReactions = [];
|
|
promise.rejectReactions = [];
|
|
promise.result = undefined;
|
|
var resolve = createResolvePromiseFunction(promise);
|
|
var reject = createRejectPromiseFunction(promise);
|
|
try {
|
|
var result = resolver(resolve, reject);
|
|
} catch (e) {
|
|
rejectPromise(promise, e);
|
|
}
|
|
promise.promiseConstructor = Promise;
|
|
return promise;
|
|
}
|
|
Promise.all = function (iterable) {
|
|
var deferred = getDeferred(this);
|
|
var values = [];
|
|
var countdownHolder = {
|
|
countdown: 0
|
|
};
|
|
var index = 0;
|
|
iterable.forEach(function (nextValue) {
|
|
var nextPromise = this.cast(nextValue);
|
|
var fn = createPromiseAllCountdownFunction(index, values, deferred, countdownHolder);
|
|
nextPromise.then(fn, deferred.reject);
|
|
index++;
|
|
countdownHolder.countdown++;
|
|
}, this);
|
|
if (index === 0) {
|
|
deferred.resolve(values);
|
|
}
|
|
return deferred.promise;
|
|
};
|
|
Promise.cast = function (x) {
|
|
if (isPromise(x)) {
|
|
return x;
|
|
}
|
|
var deferred = getDeferred(this);
|
|
deferred.resolve(x);
|
|
return deferred.promise;
|
|
};
|
|
Promise.reject = function (r) {
|
|
var deferred = getDeferred(this);
|
|
var rejectResult = deferred.reject(r);
|
|
return deferred.promise;
|
|
};
|
|
Promise.resolve = function (x) {
|
|
var deferred = getDeferred(this);
|
|
var rejectResult = deferred.resolve(x);
|
|
return deferred.promise;
|
|
};
|
|
Promise.prototype = {
|
|
'catch': function (onRejected) {
|
|
this.then(undefined, onRejected);
|
|
},
|
|
then: function (onFulfilled, onRejected) {
|
|
var promise = this;
|
|
if (!isPromise(promise)) {
|
|
throw new TypeError('this is not a Promises');
|
|
}
|
|
var cstr = promise.promiseConstructor;
|
|
var deferred = getDeferred(cstr);
|
|
var rejectionHandler = typeof onRejected === 'function' ? onRejected : throwerFunction;
|
|
var fulfillmentHandler = typeof onFulfilled === 'function' ? onFulfilled : identityFunction;
|
|
var resolutionHandler = createPromiseResolutionHandlerFunctions(promise, fulfillmentHandler, rejectionHandler);
|
|
var resolveReaction = {
|
|
deferred: deferred,
|
|
handler: resolutionHandler
|
|
};
|
|
var rejectReaction = {
|
|
deferred: deferred,
|
|
handler: rejectionHandler
|
|
};
|
|
switch (promise.promiseStatus) {
|
|
case 'unresolved':
|
|
promise.resolveReactions.push(resolveReaction);
|
|
promise.rejectReactions.push(rejectReaction);
|
|
break;
|
|
case 'has-resolution':
|
|
var resolution = promise.result;
|
|
queueMicrotask({
|
|
reaction: resolveReaction,
|
|
argument: resolution
|
|
});
|
|
break;
|
|
case 'has-rejection':
|
|
var rejection = promise.result;
|
|
queueMicrotask({
|
|
reaction: rejectReaction,
|
|
argument: rejection
|
|
});
|
|
break;
|
|
}
|
|
return deferred.promise;
|
|
}
|
|
};
|
|
global.Promise = Promise;
|
|
}());
|
|
var QuadTree = function (x, y, width, height, parent) {
|
|
this.x = x | 0;
|
|
this.y = y | 0;
|
|
this.width = width | 0;
|
|
this.height = height | 0;
|
|
if (parent) {
|
|
this.root = parent.root;
|
|
this.parent = parent;
|
|
this.level = parent.level + 1;
|
|
} else {
|
|
this.root = this;
|
|
this.parent = null;
|
|
this.level = 0;
|
|
}
|
|
this.reset();
|
|
};
|
|
QuadTree.prototype.reset = function () {
|
|
this.stuckObjects = null;
|
|
this.objects = null;
|
|
this.nodes = [];
|
|
};
|
|
QuadTree.prototype._findIndex = function (xMin, xMax, yMin, yMax) {
|
|
var midX = this.x + (this.width / 2 | 0);
|
|
var midY = this.y + (this.height / 2 | 0);
|
|
var top = yMin < midY && yMax < midY;
|
|
var bottom = yMin > midY;
|
|
if (xMin < midX && xMax < midX) {
|
|
if (top) {
|
|
return 1;
|
|
} else if (bottom) {
|
|
return 2;
|
|
}
|
|
} else if (xMin > midX) {
|
|
if (top) {
|
|
return 0;
|
|
} else if (bottom) {
|
|
return 3;
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
QuadTree.prototype.insert = function (obj) {
|
|
var nodes = this.nodes;
|
|
if (nodes.length) {
|
|
var index = this._findIndex(obj.xMin, obj.xMax, obj.yMin, obj.yMax);
|
|
if (index > -1) {
|
|
nodes[index].insert(obj);
|
|
} else {
|
|
obj.prev = null;
|
|
if (this.stuckObjects) {
|
|
obj.next = this.stuckObjects;
|
|
this.stuckObjects.prev = obj;
|
|
} else {
|
|
obj.next = null;
|
|
}
|
|
this.stuckObjects = obj;
|
|
obj.parent = this;
|
|
}
|
|
return;
|
|
}
|
|
var numChildren = 1;
|
|
var item = this.objects;
|
|
if (!item) {
|
|
obj.prev = null;
|
|
obj.next = null;
|
|
this.objects = obj;
|
|
} else {
|
|
while (item.next) {
|
|
numChildren++;
|
|
item = item.next;
|
|
}
|
|
obj.prev = item;
|
|
obj.next = null;
|
|
item.next = obj;
|
|
}
|
|
if (numChildren > 4 && this.level < 10) {
|
|
this._subdivide();
|
|
item = this.objects;
|
|
while (item) {
|
|
var next = item.next;
|
|
this.insert(item);
|
|
item = next;
|
|
}
|
|
this.objects = null;
|
|
return;
|
|
}
|
|
obj.parent = this;
|
|
};
|
|
QuadTree.prototype.update = function (obj) {
|
|
var node = obj.parent;
|
|
if (node) {
|
|
if (obj.xMin >= node.x && obj.xMax <= node.x + node.width && obj.yMin >= node.y && obj.yMax <= node.y + node.height) {
|
|
if (node.nodes.length) {
|
|
var index = this._findIndex(obj.xMin, obj.xMax, obj.yMin, obj.yMax);
|
|
if (index > -1) {
|
|
node.remove(obj);
|
|
node = this.nodes[index];
|
|
node.insert(obj);
|
|
}
|
|
} else {
|
|
node.remove(obj);
|
|
node.insert(obj);
|
|
}
|
|
return;
|
|
}
|
|
node.remove(obj);
|
|
}
|
|
this.root.insert(obj);
|
|
};
|
|
QuadTree.prototype.remove = function (obj) {
|
|
var prev = obj.prev;
|
|
var next = obj.next;
|
|
if (prev) {
|
|
prev.next = next;
|
|
obj.prev = null;
|
|
} else {
|
|
var node = obj.parent;
|
|
if (node.objects === obj) {
|
|
node.objects = next;
|
|
} else if (node.stuckObjects === obj) {
|
|
node.stuckObjects = next;
|
|
}
|
|
}
|
|
if (next) {
|
|
next.prev = prev;
|
|
obj.next = null;
|
|
}
|
|
obj.parent = null;
|
|
};
|
|
QuadTree.prototype.retrieve = function (xMin, xMax, yMin, yMax) {
|
|
var stack = [];
|
|
var out = [];
|
|
var node = this;
|
|
do {
|
|
if (node.nodes.length) {
|
|
var index = node._findIndex(xMin, xMax, yMin, yMax);
|
|
if (index > -1) {
|
|
stack.push(node.nodes[index]);
|
|
} else {
|
|
stack.push.apply(stack, node.nodes);
|
|
}
|
|
}
|
|
var item = node.objects;
|
|
for (var i = 0; i < 2; i++) {
|
|
while (item) {
|
|
if (!(item.xMin > xMax || item.xMax < xMin || item.yMin > yMax || item.yMax < yMin)) {
|
|
out.push(item);
|
|
}
|
|
item = item.next;
|
|
}
|
|
item = node.stuckObjects;
|
|
}
|
|
node = stack.pop();
|
|
} while (node);
|
|
return out;
|
|
};
|
|
QuadTree.prototype._subdivide = function () {
|
|
var halfWidth = this.width / 2 | 0;
|
|
var halfHeight = this.height / 2 | 0;
|
|
var midX = this.x + halfWidth;
|
|
var midY = this.y + halfHeight;
|
|
this.nodes[0] = new QuadTree(midX, this.y, halfWidth, halfHeight, this);
|
|
this.nodes[1] = new QuadTree(this.x, this.y, halfWidth, halfHeight, this);
|
|
this.nodes[2] = new QuadTree(this.x, midY, halfWidth, halfHeight, this);
|
|
this.nodes[3] = new QuadTree(midX, midY, halfWidth, halfHeight, this);
|
|
};
|
|
var RegionCluster = function () {
|
|
this.regions = [];
|
|
};
|
|
RegionCluster.prototype.reset = function () {
|
|
this.regions.length = 0;
|
|
};
|
|
RegionCluster.prototype.insert = function (region) {
|
|
var regions = this.regions;
|
|
if (regions.length < 3) {
|
|
regions.push({
|
|
xMin: region.xMin,
|
|
xMax: region.xMax,
|
|
yMin: region.yMin,
|
|
yMax: region.yMax
|
|
});
|
|
return;
|
|
}
|
|
var a = region;
|
|
var b = regions[0];
|
|
var c = regions[1];
|
|
var d = regions[2];
|
|
var ab = (max(a.xMax, b.xMax) - min(a.xMin, b.xMin)) * (max(a.yMax, b.yMax) - min(a.yMin, b.yMin));
|
|
var rb = regions[0];
|
|
var ac = (max(a.xMax, c.xMax) - min(a.xMin, c.xMin)) * (max(a.yMax, c.yMax) - min(a.yMin, c.yMin));
|
|
var ad = (max(a.xMax, d.xMax) - min(a.xMin, d.xMin)) * (max(a.yMax, d.yMax) - min(a.yMin, d.yMin));
|
|
if (ac < ab) {
|
|
ab = ac;
|
|
rb = c;
|
|
}
|
|
if (ad < ab) {
|
|
ab = ad;
|
|
rb = d;
|
|
}
|
|
var bc = (max(b.xMax, c.xMax) - min(b.xMin, c.xMin)) * (max(b.yMax, c.yMax) - min(b.yMin, c.yMin));
|
|
var bd = (max(b.xMax, d.xMax) - min(b.xMin, d.xMin)) * (max(b.yMax, d.yMax) - min(b.yMin, d.yMin));
|
|
var cd = (max(c.xMax, d.xMax) - min(c.xMin, d.xMin)) * (max(c.yMax, d.yMax) - min(c.yMin, d.yMin));
|
|
if (ab < bc && ab < bd && ab < cd) {
|
|
if (a.xMin < rb.xMin) {
|
|
rb.xMin = a.xMin;
|
|
}
|
|
if (a.xMax > rb.xMax) {
|
|
rb.xMax = a.xMax;
|
|
}
|
|
if (a.yMin < rb.yMin) {
|
|
rb.yMin = a.yMin;
|
|
}
|
|
if (a.yMax > rb.yMax) {
|
|
rb.yMax = a.yMax;
|
|
}
|
|
return;
|
|
}
|
|
rb = regions[0];
|
|
var rc = regions[1];
|
|
if (bd < bc) {
|
|
bc = bd;
|
|
rc = regions[2];
|
|
}
|
|
if (cd < bc) {
|
|
rb = regions[1];
|
|
rc = regions[2];
|
|
}
|
|
if (rc.xMin < rb.xMin) {
|
|
rb.xMin = rc.xMin;
|
|
}
|
|
if (rc.xMax > rb.xMax) {
|
|
rb.xMax = rc.xMax;
|
|
}
|
|
if (rc.yMin < rb.yMin) {
|
|
rb.yMin = rc.yMin;
|
|
}
|
|
if (rc.yMax > rb.yMax) {
|
|
rb.yMax = rc.yMax;
|
|
}
|
|
rc.xMin = a.xMin;
|
|
rc.xMax = a.xMax;
|
|
rc.yMin = a.yMin;
|
|
rc.yMax = a.yMax;
|
|
};
|
|
RegionCluster.prototype.retrieve = function () {
|
|
return this.regions;
|
|
};
|
|
var EXTERNAL_INTERFACE_FEATURE = 1;
|
|
var CLIPBOARD_FEATURE = 2;
|
|
var SHAREDOBJECT_FEATURE = 3;
|
|
var VIDEO_FEATURE = 4;
|
|
var SOUND_FEATURE = 5;
|
|
var NETCONNECTION_FEATURE = 6;
|
|
if (!this.performance) {
|
|
this.performance = {};
|
|
}
|
|
if (!this.performance.now) {
|
|
this.performance.now = Date.now;
|
|
}
|
|
var SWF_TAG_CODE_CSM_TEXT_SETTINGS = 74;
|
|
var SWF_TAG_CODE_DEFINE_BINARY_DATA = 87;
|
|
var SWF_TAG_CODE_DEFINE_BITS = 6;
|
|
var SWF_TAG_CODE_DEFINE_BITS_JPEG2 = 21;
|
|
var SWF_TAG_CODE_DEFINE_BITS_JPEG3 = 35;
|
|
var SWF_TAG_CODE_DEFINE_BITS_JPEG4 = 90;
|
|
var SWF_TAG_CODE_DEFINE_BITS_LOSSLESS = 20;
|
|
var SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2 = 36;
|
|
var SWF_TAG_CODE_DEFINE_BUTTON = 7;
|
|
var SWF_TAG_CODE_DEFINE_BUTTON2 = 34;
|
|
var SWF_TAG_CODE_DEFINE_BUTTON_CXFORM = 23;
|
|
var SWF_TAG_CODE_DEFINE_BUTTON_SOUND = 17;
|
|
var SWF_TAG_CODE_DEFINE_EDIT_TEXT = 37;
|
|
var SWF_TAG_CODE_DEFINE_FONT = 10;
|
|
var SWF_TAG_CODE_DEFINE_FONT2 = 48;
|
|
var SWF_TAG_CODE_DEFINE_FONT3 = 75;
|
|
var SWF_TAG_CODE_DEFINE_FONT4 = 91;
|
|
var SWF_TAG_CODE_DEFINE_FONT_ALIGN_ZONES = 73;
|
|
var SWF_TAG_CODE_DEFINE_FONT_INFO = 13;
|
|
var SWF_TAG_CODE_DEFINE_FONT_INFO2 = 62;
|
|
var SWF_TAG_CODE_DEFINE_FONT_NAME = 88;
|
|
var SWF_TAG_CODE_DEFINE_MORPH_SHAPE = 46;
|
|
var SWF_TAG_CODE_DEFINE_MORPH_SHAPE2 = 84;
|
|
var SWF_TAG_CODE_DEFINE_SCALING_GRID = 78;
|
|
var SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA = 86;
|
|
var SWF_TAG_CODE_DEFINE_SHAPE = 2;
|
|
var SWF_TAG_CODE_DEFINE_SHAPE2 = 22;
|
|
var SWF_TAG_CODE_DEFINE_SHAPE3 = 32;
|
|
var SWF_TAG_CODE_DEFINE_SHAPE4 = 83;
|
|
var SWF_TAG_CODE_DEFINE_SOUND = 14;
|
|
var SWF_TAG_CODE_DEFINE_SPRITE = 39;
|
|
var SWF_TAG_CODE_DEFINE_TEXT = 11;
|
|
var SWF_TAG_CODE_DEFINE_TEXT2 = 33;
|
|
var SWF_TAG_CODE_DEFINE_VIDEO_STREAM = 60;
|
|
var SWF_TAG_CODE_DO_ABC = 82;
|
|
var SWF_TAG_CODE_DO_ABC_ = 72;
|
|
var SWF_TAG_CODE_DO_ACTION = 12;
|
|
var SWF_TAG_CODE_DO_INIT_ACTION = 59;
|
|
var SWF_TAG_CODE_ENABLE_DEBUGGER = 58;
|
|
var SWF_TAG_CODE_ENABLE_DEBUGGER2 = 64;
|
|
var SWF_TAG_CODE_END = 0;
|
|
var SWF_TAG_CODE_EXPORT_ASSETS = 56;
|
|
var SWF_TAG_CODE_FILE_ATTRIBUTES = 69;
|
|
var SWF_TAG_CODE_FRAME_LABEL = 43;
|
|
var SWF_TAG_CODE_IMPORT_ASSETS = 57;
|
|
var SWF_TAG_CODE_IMPORT_ASSETS2 = 71;
|
|
var SWF_TAG_CODE_JPEG_TABLES = 8;
|
|
var SWF_TAG_CODE_METADATA = 77;
|
|
var SWF_TAG_CODE_PLACE_OBJECT = 4;
|
|
var SWF_TAG_CODE_PLACE_OBJECT2 = 26;
|
|
var SWF_TAG_CODE_PLACE_OBJECT3 = 70;
|
|
var SWF_TAG_CODE_PROTECT = 24;
|
|
var SWF_TAG_CODE_REMOVE_OBJECT = 5;
|
|
var SWF_TAG_CODE_REMOVE_OBJECT2 = 28;
|
|
var SWF_TAG_CODE_SCRIPT_LIMITS = 65;
|
|
var SWF_TAG_CODE_SET_BACKGROUND_COLOR = 9;
|
|
var SWF_TAG_CODE_SET_TAB_INDEX = 66;
|
|
var SWF_TAG_CODE_SHOW_FRAME = 1;
|
|
var SWF_TAG_CODE_SOUND_STREAM_BLOCK = 19;
|
|
var SWF_TAG_CODE_SOUND_STREAM_HEAD = 18;
|
|
var SWF_TAG_CODE_SOUND_STREAM_HEAD2 = 45;
|
|
var SWF_TAG_CODE_START_SOUND = 15;
|
|
var SWF_TAG_CODE_START_SOUND2 = 89;
|
|
var SWF_TAG_CODE_SYMBOL_CLASS = 76;
|
|
var SWF_TAG_CODE_VIDEO_FRAME = 61;
|
|
self.SWF = {};
|
|
var codeLengthOrder = [
|
|
16,
|
|
17,
|
|
18,
|
|
0,
|
|
8,
|
|
7,
|
|
9,
|
|
6,
|
|
10,
|
|
5,
|
|
11,
|
|
4,
|
|
12,
|
|
3,
|
|
13,
|
|
2,
|
|
14,
|
|
1,
|
|
15
|
|
];
|
|
var distanceCodes = [];
|
|
var distanceExtraBits = [];
|
|
for (var i = 0, j = 0, code = 1; i < 30; ++i) {
|
|
distanceCodes[i] = code;
|
|
code += 1 << (distanceExtraBits[i] = ~(~((j += i > 2 ? 1 : 0) / 2)));
|
|
}
|
|
var bitLengths = [];
|
|
for (var i = 0; i < 32; ++i)
|
|
bitLengths[i] = 5;
|
|
var fixedDistanceTable = makeHuffmanTable(bitLengths);
|
|
var lengthCodes = [];
|
|
var lengthExtraBits = [];
|
|
for (var i = 0, j = 0, code = 3; i < 29; ++i) {
|
|
lengthCodes[i] = code - (i == 28 ? 1 : 0);
|
|
code += 1 << (lengthExtraBits[i] = ~(~((j += i > 4 ? 1 : 0) / 4 % 6)));
|
|
}
|
|
for (var i = 0; i < 288; ++i)
|
|
bitLengths[i] = i < 144 || i > 279 ? 8 : i < 256 ? 9 : 7;
|
|
var fixedLiteralTable = makeHuffmanTable(bitLengths);
|
|
function makeHuffmanTable(bitLengths) {
|
|
var maxBits = Math.max.apply(null, bitLengths);
|
|
var numLengths = bitLengths.length;
|
|
var size = 1 << maxBits;
|
|
var codes = new Uint32Array(size);
|
|
for (var code = 0, len = 1, skip = 2; len <= maxBits; code <<= 1, ++len, skip <<= 1) {
|
|
for (var val = 0; val < numLengths; ++val) {
|
|
if (bitLengths[val] === len) {
|
|
var lsb = 0;
|
|
for (var i = 0; i < len; ++i)
|
|
lsb = lsb * 2 + (code >> i & 1);
|
|
for (var i = lsb; i < size; i += skip)
|
|
codes[i] = len << 16 | val;
|
|
++code;
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
codes: codes,
|
|
maxBits: maxBits
|
|
};
|
|
}
|
|
function verifyDeflateHeader(bytes) {
|
|
var header = bytes[0] << 8 | bytes[1];
|
|
}
|
|
function createInflatedStream(bytes, outputLength) {
|
|
verifyDeflateHeader(bytes);
|
|
var stream = new Stream(bytes, 2);
|
|
var output = {
|
|
data: new Uint8Array(outputLength),
|
|
available: 0,
|
|
completed: false
|
|
};
|
|
var state = {
|
|
header: null,
|
|
distanceTable: null,
|
|
literalTable: null,
|
|
sym: null,
|
|
len: null,
|
|
sym2: null
|
|
};
|
|
do {
|
|
inflateBlock(stream, output, state);
|
|
} while (!output.completed && stream.pos < stream.end);
|
|
return new Stream(output.data, 0, output.available);
|
|
}
|
|
var InflateNoDataError = {};
|
|
function inflateBlock(stream, output, state) {
|
|
var header = state.header !== null ? state.header : state.header = readBits(stream.bytes, stream, 3);
|
|
switch (header >> 1) {
|
|
case 0:
|
|
stream.align();
|
|
var pos = stream.pos;
|
|
if (stream.end - pos < 4) {
|
|
throw InflateNoDataError;
|
|
}
|
|
var len = stream.getUint16(pos, true);
|
|
var nlen = stream.getUint16(pos + 2, true);
|
|
if (stream.end - pos < 4 + len) {
|
|
throw InflateNoDataError;
|
|
}
|
|
var begin = pos + 4;
|
|
var end = stream.pos = begin + len;
|
|
var sbytes = stream.bytes, dbytes = output.data;
|
|
dbytes.set(sbytes.subarray(begin, end), output.available);
|
|
output.available += len;
|
|
break;
|
|
case 1:
|
|
inflate(stream, output, fixedLiteralTable, fixedDistanceTable, state);
|
|
break;
|
|
case 2:
|
|
var distanceTable, literalTable;
|
|
if (state.distanceTable !== null) {
|
|
distanceTable = state.distanceTable;
|
|
literalTable = state.literalTable;
|
|
} else {
|
|
var sbytes = stream.bytes;
|
|
var savedBufferPos = stream.pos;
|
|
var savedBitBuffer = stream.bitBuffer;
|
|
var savedBitLength = stream.bitLength;
|
|
var bitLengths = [];
|
|
var numLiteralCodes, numDistanceCodes;
|
|
try {
|
|
numLiteralCodes = readBits(sbytes, stream, 5) + 257;
|
|
numDistanceCodes = readBits(sbytes, stream, 5) + 1;
|
|
var numCodes = numLiteralCodes + numDistanceCodes;
|
|
var numLengthCodes = readBits(sbytes, stream, 4) + 4;
|
|
for (var i = 0; i < 19; ++i)
|
|
bitLengths[codeLengthOrder[i]] = i < numLengthCodes ? readBits(sbytes, stream, 3) : 0;
|
|
var codeLengthTable = makeHuffmanTable(bitLengths);
|
|
bitLengths = [];
|
|
var i = 0;
|
|
var prev = 0;
|
|
while (i < numCodes) {
|
|
var j = 1;
|
|
var sym = readCode(sbytes, stream, codeLengthTable);
|
|
switch (sym) {
|
|
case 16:
|
|
j = readBits(sbytes, stream, 2) + 3;
|
|
sym = prev;
|
|
break;
|
|
case 17:
|
|
j = readBits(sbytes, stream, 3) + 3;
|
|
sym = 0;
|
|
break;
|
|
case 18:
|
|
j = readBits(sbytes, stream, 7) + 11;
|
|
sym = 0;
|
|
break;
|
|
default:
|
|
prev = sym;
|
|
}
|
|
while (j--)
|
|
bitLengths[i++] = sym;
|
|
}
|
|
} catch (e) {
|
|
stream.pos = savedBufferPos;
|
|
stream.bitBuffer = savedBitBuffer;
|
|
stream.bitLength = savedBitLength;
|
|
throw e;
|
|
}
|
|
distanceTable = state.distanceTable = makeHuffmanTable(bitLengths.splice(numLiteralCodes, numDistanceCodes));
|
|
literalTable = state.literalTable = makeHuffmanTable(bitLengths);
|
|
}
|
|
inflate(stream, output, literalTable, distanceTable, state);
|
|
state.distanceTable = null;
|
|
state.literalTable = null;
|
|
break;
|
|
default:
|
|
fail('unknown block type', 'inflate');
|
|
}
|
|
state.header = null;
|
|
output.completed = !(!(header & 1));
|
|
}
|
|
function readBits(bytes, stream, size) {
|
|
var bitBuffer = stream.bitBuffer;
|
|
var bitLength = stream.bitLength;
|
|
if (size > bitLength) {
|
|
var pos = stream.pos;
|
|
var end = stream.end;
|
|
do {
|
|
if (pos >= end) {
|
|
stream.pos = pos;
|
|
stream.bitBuffer = bitBuffer;
|
|
stream.bitLength = bitLength;
|
|
throw InflateNoDataError;
|
|
}
|
|
bitBuffer |= bytes[pos++] << bitLength;
|
|
bitLength += 8;
|
|
} while (size > bitLength);
|
|
stream.pos = pos;
|
|
}
|
|
stream.bitBuffer = bitBuffer >>> size;
|
|
stream.bitLength = bitLength - size;
|
|
return bitBuffer & (1 << size) - 1;
|
|
}
|
|
function inflate(stream, output, literalTable, distanceTable, state) {
|
|
var pos = output.available;
|
|
var dbytes = output.data;
|
|
var sbytes = stream.bytes;
|
|
var sym = state.sym !== null ? state.sym : readCode(sbytes, stream, literalTable);
|
|
while (sym !== 256) {
|
|
if (sym < 256) {
|
|
dbytes[pos++] = sym;
|
|
} else {
|
|
state.sym = sym;
|
|
sym -= 257;
|
|
var len = state.len !== null ? state.len : state.len = lengthCodes[sym] + readBits(sbytes, stream, lengthExtraBits[sym]);
|
|
var sym2 = state.sym2 !== null ? state.sym2 : state.sym2 = readCode(sbytes, stream, distanceTable);
|
|
var distance = distanceCodes[sym2] + readBits(sbytes, stream, distanceExtraBits[sym2]);
|
|
var i = pos - distance;
|
|
while (len--)
|
|
dbytes[pos++] = dbytes[i++];
|
|
state.sym2 = null;
|
|
state.len = null;
|
|
state.sym = null;
|
|
}
|
|
output.available = pos;
|
|
sym = readCode(sbytes, stream, literalTable);
|
|
}
|
|
}
|
|
function readCode(bytes, stream, codeTable) {
|
|
var bitBuffer = stream.bitBuffer;
|
|
var bitLength = stream.bitLength;
|
|
var maxBits = codeTable.maxBits;
|
|
if (maxBits > bitLength) {
|
|
var pos = stream.pos;
|
|
var end = stream.end;
|
|
do {
|
|
if (pos >= end) {
|
|
stream.pos = pos;
|
|
stream.bitBuffer = bitBuffer;
|
|
stream.bitLength = bitLength;
|
|
throw InflateNoDataError;
|
|
}
|
|
bitBuffer |= bytes[pos++] << bitLength;
|
|
bitLength += 8;
|
|
} while (maxBits > bitLength);
|
|
stream.pos = pos;
|
|
}
|
|
var code = codeTable.codes[bitBuffer & (1 << maxBits) - 1];
|
|
var len = code >> 16;
|
|
stream.bitBuffer = bitBuffer >>> len;
|
|
stream.bitLength = bitLength - len;
|
|
return code & 65535;
|
|
}
|
|
var StreamNoDataError = {};
|
|
var Stream = function StreamClosure() {
|
|
function Stream_align() {
|
|
this.bitBuffer = this.bitLength = 0;
|
|
}
|
|
function Stream_ensure(size) {
|
|
if (this.pos + size > this.end) {
|
|
throw StreamNoDataError;
|
|
}
|
|
}
|
|
function Stream_remaining() {
|
|
return this.end - this.pos;
|
|
}
|
|
function Stream_substream(begin, end) {
|
|
var stream = new Stream(this.bytes);
|
|
stream.pos = begin;
|
|
stream.end = end;
|
|
return stream;
|
|
}
|
|
function Stream_push(data) {
|
|
var bytes = this.bytes;
|
|
var newBytesLength = this.end + data.length;
|
|
if (newBytesLength > bytes.length) {
|
|
throw 'stream buffer overfow';
|
|
}
|
|
bytes.set(data, this.end);
|
|
this.end = newBytesLength;
|
|
}
|
|
function Stream(buffer, offset, length, maxLength) {
|
|
if (offset === undefined)
|
|
offset = 0;
|
|
if (buffer.buffer instanceof ArrayBuffer) {
|
|
offset += buffer.byteOffset;
|
|
buffer = buffer.buffer;
|
|
}
|
|
if (length === undefined)
|
|
length = buffer.byteLength - offset;
|
|
if (maxLength === undefined)
|
|
maxLength = length;
|
|
var bytes = new Uint8Array(buffer, offset, maxLength);
|
|
var stream = new DataView(buffer, offset, maxLength);
|
|
stream.bytes = bytes;
|
|
stream.pos = 0;
|
|
stream.end = length;
|
|
stream.bitBuffer = 0;
|
|
stream.bitLength = 0;
|
|
stream.align = Stream_align;
|
|
stream.ensure = Stream_ensure;
|
|
stream.remaining = Stream_remaining;
|
|
stream.substream = Stream_substream;
|
|
stream.push = Stream_push;
|
|
return stream;
|
|
}
|
|
return Stream;
|
|
}();
|
|
var FORMAT_COLORMAPPED = 3;
|
|
var FORMAT_15BPP = 4;
|
|
var FORMAT_24BPP = 5;
|
|
var FACTOR_5BBP = 255 / 31;
|
|
var crcTable = [];
|
|
for (var i = 0; i < 256; i++) {
|
|
var c = i;
|
|
for (var h = 0; h < 8; h++) {
|
|
if (c & 1)
|
|
c = 3988292384 ^ c >> 1 & 2147483647;
|
|
else
|
|
c = c >> 1 & 2147483647;
|
|
}
|
|
crcTable[i] = c;
|
|
}
|
|
function crc32(data, start, end) {
|
|
var crc = -1;
|
|
for (var i = start; i < end; i++) {
|
|
var a = (crc ^ data[i]) & 255;
|
|
var b = crcTable[a];
|
|
crc = crc >>> 8 ^ b;
|
|
}
|
|
return crc ^ -1;
|
|
}
|
|
function createPngChunk(type, data) {
|
|
var chunk = new Uint8Array(12 + data.length);
|
|
var p = 0;
|
|
var len = data.length;
|
|
chunk[p] = len >> 24 & 255;
|
|
chunk[p + 1] = len >> 16 & 255;
|
|
chunk[p + 2] = len >> 8 & 255;
|
|
chunk[p + 3] = len & 255;
|
|
chunk[p + 4] = type.charCodeAt(0) & 255;
|
|
chunk[p + 5] = type.charCodeAt(1) & 255;
|
|
chunk[p + 6] = type.charCodeAt(2) & 255;
|
|
chunk[p + 7] = type.charCodeAt(3) & 255;
|
|
if (data instanceof Uint8Array)
|
|
chunk.set(data, 8);
|
|
p = 8 + len;
|
|
var crc = crc32(chunk, 4, p);
|
|
chunk[p] = crc >> 24 & 255;
|
|
chunk[p + 1] = crc >> 16 & 255;
|
|
chunk[p + 2] = crc >> 8 & 255;
|
|
chunk[p + 3] = crc & 255;
|
|
return chunk;
|
|
}
|
|
function adler32(data, start, end) {
|
|
var a = 1;
|
|
var b = 0;
|
|
for (var i = start; i < end; ++i) {
|
|
a = (a + (data[i] & 255)) % 65521;
|
|
b = (b + a) % 65521;
|
|
}
|
|
return b << 16 | a;
|
|
}
|
|
function defineBitmap(tag) {
|
|
var width = tag.width;
|
|
var height = tag.height;
|
|
var hasAlpha = tag.hasAlpha;
|
|
var plte = '';
|
|
var trns = '';
|
|
var literals;
|
|
var bmpData = tag.bmpData;
|
|
switch (tag.format) {
|
|
case FORMAT_COLORMAPPED:
|
|
var colorType = 3;
|
|
var bytesPerLine = width + 3 & ~3;
|
|
var colorTableSize = tag.colorTableSize + 1;
|
|
var paletteSize = colorTableSize * (tag.hasAlpha ? 4 : 3);
|
|
var datalen = paletteSize + bytesPerLine * height;
|
|
var stream = createInflatedStream(bmpData, datalen);
|
|
var bytes = stream.bytes;
|
|
var pos = 0;
|
|
stream.ensure(paletteSize);
|
|
if (hasAlpha) {
|
|
var palette = new Uint8Array(paletteSize / 4 * 3);
|
|
var pp = 0;
|
|
var alphaValues = new Uint8Array(paletteSize / 4);
|
|
var pa = 0;
|
|
while (pos < paletteSize) {
|
|
palette[pp++] = bytes[pos];
|
|
palette[pp++] = bytes[pos + 1];
|
|
palette[pp++] = bytes[pos + 2];
|
|
alphaValues[pa++] = bytes[pos + 3];
|
|
pos += 4;
|
|
}
|
|
plte = createPngChunk('PLTE', palette);
|
|
trns = createPngChunk('tRNS', alphaValues);
|
|
} else {
|
|
plte = createPngChunk('PLTE', bytes.subarray(pos, pos + paletteSize));
|
|
pos += paletteSize;
|
|
}
|
|
literals = new Uint8Array(width * height + height);
|
|
var pl = 0;
|
|
while (pos < datalen) {
|
|
stream.ensure(bytesPerLine);
|
|
var begin = pos;
|
|
var end = begin + width;
|
|
pl++;
|
|
literals.set(bytes.subarray(begin, end), pl);
|
|
pl += end - begin;
|
|
stream.pos = pos += bytesPerLine;
|
|
}
|
|
break;
|
|
case FORMAT_15BPP:
|
|
var colorType = 2;
|
|
var bytesPerLine = width * 2 + 3 & ~3;
|
|
var stream = createInflatedStream(bmpData, bytesPerLine * height);
|
|
var pos = 0;
|
|
literals = new Uint8Array(width * height * 3 + height);
|
|
var pl = 0;
|
|
for (var y = 0; y < height; ++y) {
|
|
pl++;
|
|
stream.ensure(bytesPerLine);
|
|
for (var x = 0; x < width; ++x) {
|
|
var word = stream.getUint16(pos);
|
|
pos += 2;
|
|
literals[pl++] = 0 | FACTOR_5BBP * (word >> 10 & 31);
|
|
literals[pl++] = 0 | FACTOR_5BBP * (word >> 5 & 31);
|
|
literals[pl++] = 0 | FACTOR_5BBP * (word & 31);
|
|
}
|
|
stream.pos = pos += bytesPerLine;
|
|
}
|
|
break;
|
|
case FORMAT_24BPP:
|
|
var padding;
|
|
if (hasAlpha) {
|
|
var colorType = 6;
|
|
padding = 0;
|
|
literals = new Uint8Array(width * height * 4 + height);
|
|
} else {
|
|
var colorType = 2;
|
|
padding = 1;
|
|
literals = new Uint8Array(width * height * 3 + height);
|
|
}
|
|
var bytesPerLine = width * 4;
|
|
var stream = createInflatedStream(bmpData, bytesPerLine * height);
|
|
var bytes = stream.bytes;
|
|
var pos = 0;
|
|
var pl = 0;
|
|
for (var y = 0; y < height; ++y) {
|
|
stream.ensure(bytesPerLine);
|
|
pl++;
|
|
for (var x = 0; x < width; ++x) {
|
|
pos += padding;
|
|
if (hasAlpha) {
|
|
var alpha = bytes[pos];
|
|
if (alpha) {
|
|
var opacity = alpha / 255;
|
|
literals[pl++] = 0 | bytes[pos + 1] / opacity;
|
|
literals[pl++] = 0 | bytes[pos + 2] / opacity;
|
|
literals[pl++] = 0 | bytes[pos + 3] / opacity;
|
|
literals[pl++] = alpha;
|
|
} else {
|
|
pl += 4;
|
|
}
|
|
} else {
|
|
literals[pl++] = bytes[pos];
|
|
literals[pl++] = bytes[pos + 1];
|
|
literals[pl++] = bytes[pos + 2];
|
|
}
|
|
pos += 4 - padding;
|
|
}
|
|
stream.pos = pos;
|
|
}
|
|
break;
|
|
default:
|
|
fail('invalid format', 'bitmap');
|
|
}
|
|
var ihdr = new Uint8Array([
|
|
width >> 24 & 255,
|
|
width >> 16 & 255,
|
|
width >> 8 & 255,
|
|
width & 255,
|
|
height >> 24 & 255,
|
|
height >> 16 & 255,
|
|
height >> 8 & 255,
|
|
height & 255,
|
|
8,
|
|
colorType,
|
|
0,
|
|
0,
|
|
0
|
|
]);
|
|
var len = literals.length;
|
|
var maxBlockLength = 65535;
|
|
var idat = new Uint8Array(2 + len + Math.ceil(len / maxBlockLength) * 5 + 4);
|
|
var pi = 0;
|
|
idat[pi++] = 120;
|
|
idat[pi++] = 156;
|
|
var pos = 0;
|
|
while (len > maxBlockLength) {
|
|
idat[pi++] = 0;
|
|
idat[pi++] = 255;
|
|
idat[pi++] = 255;
|
|
idat[pi++] = 0;
|
|
idat[pi++] = 0;
|
|
idat.set(literals.subarray(pos, pos + maxBlockLength), pi);
|
|
pi += maxBlockLength;
|
|
pos += maxBlockLength;
|
|
len -= maxBlockLength;
|
|
}
|
|
idat[pi++] = 1;
|
|
idat[pi++] = len & 255;
|
|
idat[pi++] = len >> 8 & 255;
|
|
idat[pi++] = ~len & 65535 & 255;
|
|
idat[pi++] = (~len & 65535) >> 8 & 255;
|
|
idat.set(literals.subarray(pos), pi);
|
|
pi += literals.length - pos;
|
|
var adler = adler32(literals, 0, literals.length);
|
|
idat[pi++] = adler >> 24 & 255;
|
|
idat[pi++] = adler >> 16 & 255;
|
|
idat[pi++] = adler >> 8 & 255;
|
|
idat[pi++] = adler & 255;
|
|
var chunks = [
|
|
new Uint8Array([
|
|
137,
|
|
80,
|
|
78,
|
|
71,
|
|
13,
|
|
10,
|
|
26,
|
|
10
|
|
]),
|
|
createPngChunk('IHDR', ihdr),
|
|
plte,
|
|
trns,
|
|
createPngChunk('IDAT', idat),
|
|
createPngChunk('IEND', '')
|
|
];
|
|
return {
|
|
type: 'image',
|
|
id: tag.id,
|
|
width: width,
|
|
height: height,
|
|
mimeType: 'image/png',
|
|
data: new Blob(chunks, {
|
|
type: 'image/png'
|
|
})
|
|
};
|
|
}
|
|
function defineButton(tag, dictionary) {
|
|
var characters = tag.characters;
|
|
var states = {
|
|
up: {},
|
|
over: {},
|
|
down: {},
|
|
hitTest: {}
|
|
};
|
|
var i = 0, character;
|
|
while (character = characters[i++]) {
|
|
if (character.eob)
|
|
break;
|
|
var characterItem = dictionary[character.symbolId];
|
|
var entry = {
|
|
symbolId: characterItem.id,
|
|
hasMatrix: !(!character.matrix),
|
|
matrix: character.matrix
|
|
};
|
|
if (character.stateUp)
|
|
states.up[character.depth] = entry;
|
|
if (character.stateOver)
|
|
states.over[character.depth] = entry;
|
|
if (character.stateDown)
|
|
states.down[character.depth] = entry;
|
|
if (character.stateHitTest)
|
|
states.hitTest[character.depth] = entry;
|
|
}
|
|
var button = {
|
|
type: 'button',
|
|
id: tag.id,
|
|
buttonActions: tag.buttonActions,
|
|
states: states
|
|
};
|
|
return button;
|
|
}
|
|
var nextFontId = 1;
|
|
function maxPower2(num) {
|
|
var maxPower = 0;
|
|
var val = num;
|
|
while (val >= 2) {
|
|
val /= 2;
|
|
++maxPower;
|
|
}
|
|
return pow(2, maxPower);
|
|
}
|
|
function toString16(val) {
|
|
return fromCharCode(val >> 8 & 255, val & 255);
|
|
}
|
|
function toString32(val) {
|
|
return toString16(val >> 16) + toString16(val);
|
|
}
|
|
function defineFont(tag, dictionary) {
|
|
var tables = {};
|
|
var codes = [];
|
|
var glyphIndex = {};
|
|
var ranges = [];
|
|
var glyphs = tag.glyphs;
|
|
var glyphCount = glyphs.length;
|
|
if (tag.codes) {
|
|
codes = codes.concat(tag.codes);
|
|
for (var i = 0, code; code = codes[i]; ++i)
|
|
glyphIndex[code] = i;
|
|
codes.sort(function (a, b) {
|
|
return a - b;
|
|
});
|
|
var i = 0;
|
|
var code;
|
|
while (code = codes[i++]) {
|
|
var start = code;
|
|
var end = start;
|
|
var indices = [
|
|
i - 1
|
|
];
|
|
while ((code = codes[i]) && end + 1 === code) {
|
|
++end;
|
|
indices.push(i);
|
|
++i;
|
|
}
|
|
ranges.push([
|
|
start,
|
|
end,
|
|
indices
|
|
]);
|
|
}
|
|
} else {
|
|
var indices = [];
|
|
var UAC_OFFSET = 57344;
|
|
for (var i = 0; i < glyphCount; i++) {
|
|
var code = UAC_OFFSET + i;
|
|
codes.push(code);
|
|
glyphIndex[code] = i;
|
|
indices.push(i);
|
|
}
|
|
ranges.push([
|
|
UAC_OFFSET,
|
|
UAC_OFFSET + glyphCount - 1,
|
|
indices
|
|
]);
|
|
}
|
|
var resolution = tag.resolution || 1;
|
|
var ascent = Math.ceil(tag.ascent / resolution) || 1024;
|
|
var descent = -Math.ceil(tag.descent / resolution) | 0;
|
|
var leading = tag.leading / resolution | 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';
|
|
;
|
|
var startCount = '';
|
|
var endCount = '';
|
|
var idDelta = '';
|
|
var idRangeOffset = '';
|
|
var i = 0;
|
|
var range;
|
|
while (range = ranges[i++]) {
|
|
var start = range[0];
|
|
var end = range[1];
|
|
var code = range[2][0];
|
|
startCount += toString16(start);
|
|
endCount += toString16(end);
|
|
idDelta += toString16(code - start + 1 & 65535);
|
|
idRangeOffset += toString16(0);
|
|
}
|
|
endCount += '\xff\xff';
|
|
startCount += '\xff\xff';
|
|
idDelta += '\0\x01';
|
|
idRangeOffset += '\0\0';
|
|
var segCount = ranges.length + 1;
|
|
var searchRange = maxPower2(segCount) * 2;
|
|
var rangeShift = 2 * segCount - searchRange;
|
|
var format314 = '\0\0' + toString16(segCount * 2) + toString16(searchRange) + toString16(logE(segCount) / logE(2)) + toString16(rangeShift) + endCount + '\0\0' + startCount + idDelta + idRangeOffset;
|
|
;
|
|
tables['cmap'] = '\0\0\0\x01\0\x03\0\x01\0\0\0\f\0\x04' + toString16(format314.length + 4) + format314;
|
|
;
|
|
var glyf = '\0\x01\0\0\0\0\0\0\0\0\0\0\0\x001\0';
|
|
var loca = '\0\0';
|
|
var offset = 16;
|
|
var maxPoints = 0;
|
|
var xMins = [];
|
|
var xMaxs = [];
|
|
var yMins = [];
|
|
var yMaxs = [];
|
|
var maxContours = 0;
|
|
var i = 0;
|
|
var code;
|
|
while (code = codes[i++]) {
|
|
var glyph = glyphs[glyphIndex[code]];
|
|
var records = glyph.records;
|
|
var numberOfContours = 1;
|
|
var endPoint = 0;
|
|
var endPtsOfContours = '';
|
|
var flags = '';
|
|
var xCoordinates = '';
|
|
var yCoordinates = '';
|
|
var x = 0;
|
|
var y = 0;
|
|
var xMin = 1024;
|
|
var xMax = -1024;
|
|
var yMin = 1024;
|
|
var yMax = -1024;
|
|
for (var j = 0, record; record = records[j]; ++j) {
|
|
if (record.type) {
|
|
if (record.isStraight) {
|
|
if (record.isGeneral) {
|
|
flags += '\x01';
|
|
var dx = record.deltaX / resolution;
|
|
var dy = -record.deltaY / resolution;
|
|
xCoordinates += toString16(dx);
|
|
yCoordinates += toString16(dy);
|
|
x += dx;
|
|
y += dy;
|
|
} else if (record.isVertical) {
|
|
flags += '\x11';
|
|
var dy = -record.deltaY / resolution;
|
|
yCoordinates += toString16(dy);
|
|
y += dy;
|
|
} else {
|
|
flags += '!';
|
|
var dx = record.deltaX / resolution;
|
|
xCoordinates += toString16(dx);
|
|
x += dx;
|
|
}
|
|
} else {
|
|
flags += '\0';
|
|
var cx = record.controlDeltaX / resolution;
|
|
var cy = -record.controlDeltaY / resolution;
|
|
xCoordinates += toString16(cx);
|
|
yCoordinates += toString16(cy);
|
|
flags += '\x01';
|
|
var dx = record.anchorDeltaX / resolution;
|
|
var dy = -record.anchorDeltaY / resolution;
|
|
xCoordinates += toString16(dx);
|
|
yCoordinates += toString16(dy);
|
|
++endPoint;
|
|
x += cx + dx;
|
|
y += cy + dy;
|
|
}
|
|
if (x < xMin)
|
|
xMin = x;
|
|
if (x > xMax)
|
|
xMax = x;
|
|
if (y < yMin)
|
|
yMin = y;
|
|
if (y > yMax)
|
|
yMax = y;
|
|
++endPoint;
|
|
} else {
|
|
if (record.eos)
|
|
break;
|
|
if (record.move) {
|
|
if (endPoint) {
|
|
++numberOfContours;
|
|
endPtsOfContours += toString16(endPoint - 1);
|
|
}
|
|
flags += '\x01';
|
|
var moveX = record.moveX / resolution;
|
|
var moveY = -record.moveY / resolution;
|
|
var dx = moveX - x;
|
|
var dy = moveY - y;
|
|
xCoordinates += toString16(dx);
|
|
yCoordinates += toString16(dy);
|
|
x = moveX;
|
|
y = moveY;
|
|
if (endPoint > maxPoints)
|
|
maxPoints = endPoint;
|
|
if (x < xMin)
|
|
xMin = x;
|
|
if (x > xMax)
|
|
xMax = x;
|
|
if (y < yMin)
|
|
yMin = y;
|
|
if (y > yMax)
|
|
yMax = y;
|
|
++endPoint;
|
|
}
|
|
}
|
|
}
|
|
endPtsOfContours += toString16((endPoint || 1) - 1);
|
|
if (!j) {
|
|
xMin = xMax = yMin = yMax = 0;
|
|
flags += '1';
|
|
}
|
|
var entry = toString16(numberOfContours) + toString16(xMin) + toString16(yMin) + toString16(xMax) + toString16(yMax) + endPtsOfContours + '\0\0' + flags + xCoordinates + yCoordinates;
|
|
;
|
|
if (entry.length & 1)
|
|
entry += '\0';
|
|
glyf += entry;
|
|
loca += toString16(offset / 2);
|
|
offset += entry.length;
|
|
xMins.push(xMin);
|
|
xMaxs.push(xMax);
|
|
yMins.push(yMin);
|
|
yMaxs.push(yMax);
|
|
if (numberOfContours > maxContours)
|
|
maxContours = numberOfContours;
|
|
if (endPoint > maxPoints)
|
|
maxPoints = endPoint;
|
|
}
|
|
loca += toString16(offset / 2);
|
|
tables['glyf'] = glyf;
|
|
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';
|
|
;
|
|
var advance = tag.advance;
|
|
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);
|
|
;
|
|
var hmtx = '\0\0\0\0';
|
|
for (var i = 0; i < glyphCount; ++i)
|
|
hmtx += toString16(advance ? advance[i] / resolution : 1024) + '\0\0';
|
|
tables['hmtx'] = hmtx;
|
|
if (tag.kerning) {
|
|
var kerning = tag.kerning;
|
|
var nPairs = kerning.length;
|
|
var searchRange = maxPower2(nPairs) * 2;
|
|
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);
|
|
;
|
|
var i = 0;
|
|
var record;
|
|
while (record = kerning[i++]) {
|
|
kern += toString16(glyphIndex[record.code1]) + toString16(glyphIndex[record.code2]) + toString16(record.adjustment);
|
|
;
|
|
}
|
|
tables['kern'] = kern;
|
|
}
|
|
tables['loca'] = loca;
|
|
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';
|
|
;
|
|
var uniqueId = 'swf-font-' + nextFontId++;
|
|
var fontName = tag.name || uniqueId;
|
|
var psName = fontName.replace(/ /g, '');
|
|
var strings = [
|
|
tag.copyright || 'Original licence',
|
|
fontName,
|
|
'Unknown',
|
|
uniqueId,
|
|
fontName,
|
|
'1.0',
|
|
psName,
|
|
'Unknown',
|
|
'Unknown',
|
|
'Unknown'
|
|
];
|
|
var count = strings.length;
|
|
var name = '\0\0' + toString16(count) + toString16(count * 12 + 6);
|
|
var offset = 0;
|
|
var i = 0;
|
|
var str;
|
|
while (str = strings[i++]) {
|
|
name += '\0\x01\0\0\0\0' + toString16(i - 1) + toString16(str.length) + toString16(offset);
|
|
offset += str.length;
|
|
}
|
|
tables['name'] = name + strings.join('');
|
|
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';
|
|
;
|
|
var names = keys(tables);
|
|
var numTables = names.length;
|
|
var header = '\0\x01\0\0' + toString16(numTables) + '\0\x80' + '\0\x03' + '\0 ';
|
|
;
|
|
var data = '';
|
|
var offset = numTables * 16 + header.length;
|
|
var i = 0;
|
|
var name;
|
|
while (name = names[i++]) {
|
|
var table = tables[name];
|
|
var length = table.length;
|
|
header += name + '\0\0\0\0' + toString32(offset) + toString32(length);
|
|
;
|
|
while (length & 3) {
|
|
table += '\0';
|
|
++length;
|
|
}
|
|
data += table;
|
|
while (offset & 3)
|
|
++offset;
|
|
offset += length;
|
|
}
|
|
var otf = header + data;
|
|
var unitPerEm = 1024;
|
|
var metrics = {
|
|
ascent: ascent / unitPerEm,
|
|
descent: -descent / unitPerEm,
|
|
leading: leading / unitPerEm
|
|
};
|
|
return {
|
|
type: 'font',
|
|
id: tag.id,
|
|
name: fontName,
|
|
uniqueName: psName + uniqueId,
|
|
codes: codes,
|
|
metrics: metrics,
|
|
bold: tag.bold === 1,
|
|
italic: tag.italic === 1,
|
|
data: otf
|
|
};
|
|
}
|
|
function getUint16(buff, pos) {
|
|
return buff[pos] << 8 | buff[pos + 1];
|
|
}
|
|
function parseJpegChunks(imgDef, bytes) {
|
|
var i = 0;
|
|
var n = bytes.length;
|
|
var chunks = [];
|
|
var code;
|
|
do {
|
|
var begin = i;
|
|
while (i < n && bytes[i] !== 255)
|
|
++i;
|
|
while (i < n && bytes[i] === 255)
|
|
++i;
|
|
code = bytes[i++];
|
|
if (code === 218) {
|
|
i = n;
|
|
} else if (code === 217) {
|
|
i += 2;
|
|
continue;
|
|
} else if (code < 208 || code > 216) {
|
|
var length = getUint16(bytes, i);
|
|
if (code >= 192 && code <= 195) {
|
|
imgDef.height = getUint16(bytes, i + 3);
|
|
imgDef.width = getUint16(bytes, i + 5);
|
|
}
|
|
i += length;
|
|
}
|
|
chunks.push(bytes.subarray(begin, i));
|
|
} while (i < n);
|
|
return chunks;
|
|
}
|
|
function defineImage(tag, dictionary) {
|
|
var img = {
|
|
type: 'image',
|
|
id: tag.id,
|
|
mimeType: tag.mimeType
|
|
};
|
|
var imgData = tag.imgData;
|
|
var chunks;
|
|
if (tag.mimeType === 'image/jpeg') {
|
|
chunks = parseJpegChunks(img, imgData);
|
|
var alphaData = tag.alphaData;
|
|
if (alphaData) {
|
|
img.mask = createInflatedStream(alphaData, img.width * img.height).bytes;
|
|
}
|
|
if (tag.incomplete) {
|
|
var tables = dictionary[0];
|
|
var header = tables.data;
|
|
if (header && header.size) {
|
|
chunks[0] = chunks[0].subarray(2);
|
|
chunks.unshift(header.slice(0, header.size - 2));
|
|
}
|
|
}
|
|
} else {
|
|
chunks = [
|
|
imgData
|
|
];
|
|
}
|
|
img.data = new Blob(chunks, {
|
|
type: tag.mimeType
|
|
});
|
|
return img;
|
|
}
|
|
function defineLabel(tag, dictionary) {
|
|
var records = tag.records;
|
|
var m = tag.matrix;
|
|
var cmds = [
|
|
'c.save()',
|
|
'c.transform(' + [
|
|
m.a,
|
|
m.b,
|
|
m.c,
|
|
m.d,
|
|
m.tx / 20,
|
|
m.ty / 20
|
|
].join(',') + ')',
|
|
'c.scale(0.05, 0.05)'
|
|
];
|
|
var dependencies = [];
|
|
var x = 0;
|
|
var y = 0;
|
|
var i = 0;
|
|
var record;
|
|
var codes;
|
|
while (record = records[i++]) {
|
|
if (record.eot)
|
|
break;
|
|
if (record.hasFont) {
|
|
var font = dictionary[record.fontId];
|
|
codes = font.codes;
|
|
cmds.push('c.font="' + record.fontHeight + 'px \'' + font.uniqueName + '\'"');
|
|
dependencies.push(font.id);
|
|
}
|
|
if (record.hasColor) {
|
|
cmds.push('ct.setFillStyle(c,"' + rgbaObjToStr(record.color) + '")');
|
|
cmds.push('ct.setAlpha(c)');
|
|
} else {
|
|
cmds.push('ct.setAlpha(c,true)');
|
|
}
|
|
if (record.hasMoveX)
|
|
x = record.moveX;
|
|
if (record.hasMoveY)
|
|
y = record.moveY;
|
|
var entries = record.entries;
|
|
var j = 0;
|
|
var entry;
|
|
while (entry = entries[j++]) {
|
|
var code = codes[entry.glyphIndex];
|
|
var text = code >= 32 && code != 34 && code != 92 ? fromCharCode(code) : '\\u' + (code + 65536).toString(16).substring(1);
|
|
cmds.push('c.fillText("' + text + '",' + x + ',' + y + ')');
|
|
x += entry.advance;
|
|
}
|
|
}
|
|
cmds.push('c.restore()');
|
|
var label = {
|
|
type: 'label',
|
|
id: tag.id,
|
|
bbox: tag.bbox,
|
|
data: cmds.join('\n')
|
|
};
|
|
if (dependencies.length)
|
|
label.require = dependencies;
|
|
return label;
|
|
}
|
|
var GRAPHICS_FILL_CLIPPED_BITMAP = 65;
|
|
var GRAPHICS_FILL_FOCAL_RADIAL_GRADIENT = 19;
|
|
var GRAPHICS_FILL_LINEAR_GRADIENT = 16;
|
|
var GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP = 67;
|
|
var GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP = 66;
|
|
var GRAPHICS_FILL_RADIAL_GRADIENT = 18;
|
|
var GRAPHICS_FILL_REPEATING_BITMAP = 64;
|
|
var GRAPHICS_FILL_SOLID = 0;
|
|
function applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph) {
|
|
if (!segment) {
|
|
return;
|
|
}
|
|
var commands = segment.commands;
|
|
var data = segment.data;
|
|
var morphData = segment.morphData;
|
|
if (morphData) {
|
|
}
|
|
var path;
|
|
var targetSegment;
|
|
var command;
|
|
var i;
|
|
if (styles.fill0) {
|
|
path = fillPaths[styles.fill0 - 1];
|
|
if (!(styles.fill1 || styles.line)) {
|
|
targetSegment = path.head();
|
|
targetSegment.commands = [];
|
|
targetSegment.data = [];
|
|
targetSegment.morphData = isMorph ? [] : null;
|
|
} else {
|
|
targetSegment = path.addSegment([], [], isMorph ? [] : null);
|
|
}
|
|
var targetCommands = targetSegment.commands;
|
|
var targetData = targetSegment.data;
|
|
var targetMorphData = targetSegment.morphData;
|
|
targetCommands.push(SHAPE_MOVE_TO);
|
|
var j = data.length - 2;
|
|
targetData.push(data[j], data[j + 1]);
|
|
if (isMorph) {
|
|
targetMorphData.push(morphData[j], morphData[j + 1]);
|
|
}
|
|
for (i = commands.length; i-- > 1; j -= 2) {
|
|
command = commands[i];
|
|
targetCommands.push(command);
|
|
targetData.push(data[j - 2], data[j - 1]);
|
|
if (isMorph) {
|
|
targetMorphData.push(morphData[j - 2], morphData[j - 1]);
|
|
}
|
|
if (command === SHAPE_CURVE_TO) {
|
|
targetData.push(data[j - 4], data[j - 3]);
|
|
if (isMorph) {
|
|
targetMorphData.push(morphData[j - 4], morphData[j - 3]);
|
|
}
|
|
j -= 2;
|
|
}
|
|
}
|
|
if (isMorph) {
|
|
}
|
|
}
|
|
if (styles.line && styles.fill1) {
|
|
path = linePaths[styles.line - 1];
|
|
path.addSegment(commands, data, morphData);
|
|
}
|
|
}
|
|
function convertRecordsToStyledPaths(records, fillPaths, linePaths, dictionary, dependencies, recordsMorph, transferables) {
|
|
var isMorph = recordsMorph !== null;
|
|
var styles = {
|
|
fill0: 0,
|
|
fill1: 0,
|
|
line: 0
|
|
};
|
|
var segment = null;
|
|
var allPaths;
|
|
var defaultPath;
|
|
var numRecords = records.length - 1;
|
|
var x = 0;
|
|
var y = 0;
|
|
var morphX = 0;
|
|
var morphY = 0;
|
|
var path;
|
|
for (var i = 0, j = 0; i < numRecords; i++) {
|
|
var record = records[i];
|
|
var morphRecord;
|
|
if (isMorph) {
|
|
morphRecord = recordsMorph[j++];
|
|
}
|
|
if (record.type === 0) {
|
|
if (segment) {
|
|
applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph);
|
|
}
|
|
if (record.hasNewStyles) {
|
|
if (!allPaths) {
|
|
allPaths = [];
|
|
}
|
|
push.apply(allPaths, fillPaths);
|
|
fillPaths = createPathsList(record.fillStyles, false, dictionary, dependencies);
|
|
push.apply(allPaths, linePaths);
|
|
linePaths = createPathsList(record.lineStyles, true, dictionary, dependencies);
|
|
if (defaultPath) {
|
|
allPaths.push(defaultPath);
|
|
defaultPath = null;
|
|
}
|
|
styles = {
|
|
fill0: 0,
|
|
fill1: 0,
|
|
line: 0
|
|
};
|
|
}
|
|
if (record.hasFillStyle0) {
|
|
styles.fill0 = record.fillStyle0;
|
|
}
|
|
if (record.hasFillStyle1) {
|
|
styles.fill1 = record.fillStyle1;
|
|
}
|
|
if (record.hasLineStyle) {
|
|
styles.line = record.lineStyle;
|
|
}
|
|
if (styles.fill1) {
|
|
path = fillPaths[styles.fill1 - 1];
|
|
} else if (styles.line) {
|
|
path = linePaths[styles.line - 1];
|
|
} else if (styles.fill0) {
|
|
path = fillPaths[styles.fill0 - 1];
|
|
}
|
|
if (record.move) {
|
|
x = record.moveX | 0;
|
|
y = record.moveY | 0;
|
|
}
|
|
if (path) {
|
|
segment = path.addSegment([], [], isMorph ? [] : null);
|
|
segment.commands.push(SHAPE_MOVE_TO);
|
|
segment.data.push(x, y);
|
|
if (isMorph) {
|
|
if (morphRecord.type === 0) {
|
|
morphX = morphRecord.moveX | 0;
|
|
morphY = morphRecord.moveY | 0;
|
|
} else {
|
|
morphX = x;
|
|
morphY = y;
|
|
j--;
|
|
}
|
|
segment.morphData.push(morphX, morphY);
|
|
}
|
|
}
|
|
} else {
|
|
if (!segment) {
|
|
if (!defaultPath) {
|
|
var style = {
|
|
color: {
|
|
red: 0,
|
|
green: 0,
|
|
blue: 0,
|
|
alpha: 255
|
|
},
|
|
width: 20
|
|
};
|
|
defaultPath = new SegmentedPath(null, processStyle(style, true));
|
|
}
|
|
segment = defaultPath.addSegment([], [], isMorph ? [] : null);
|
|
segment.commands.push(SHAPE_MOVE_TO);
|
|
segment.data.push(x, y);
|
|
if (isMorph) {
|
|
segment.morphData.push(morphX, morphY);
|
|
}
|
|
}
|
|
if (isMorph) {
|
|
while (morphRecord && morphRecord.type === 0) {
|
|
morphRecord = recordsMorph[j++];
|
|
}
|
|
if (!morphRecord) {
|
|
morphRecord = record;
|
|
}
|
|
}
|
|
if (record.isStraight && (!isMorph || morphRecord.isStraight)) {
|
|
x += record.deltaX | 0;
|
|
y += record.deltaY | 0;
|
|
segment.commands.push(SHAPE_LINE_TO);
|
|
segment.data.push(x, y);
|
|
if (isMorph) {
|
|
morphX += morphRecord.deltaX | 0;
|
|
morphY += morphRecord.deltaY | 0;
|
|
segment.morphData.push(morphX, morphY);
|
|
}
|
|
} else {
|
|
var cx, cy;
|
|
var deltaX, deltaY;
|
|
if (!record.isStraight) {
|
|
cx = x + record.controlDeltaX | 0;
|
|
cy = y + record.controlDeltaY | 0;
|
|
x = cx + record.anchorDeltaX | 0;
|
|
y = cy + record.anchorDeltaY | 0;
|
|
} else {
|
|
deltaX = record.deltaX | 0;
|
|
deltaY = record.deltaY | 0;
|
|
cx = x + (deltaX >> 1);
|
|
cy = y + (deltaY >> 1);
|
|
x += deltaX;
|
|
y += deltaY;
|
|
}
|
|
segment.commands.push(SHAPE_CURVE_TO);
|
|
segment.data.push(cx, cy, x, y);
|
|
if (isMorph) {
|
|
if (!morphRecord.isStraight) {
|
|
cx = morphX + morphRecord.controlDeltaX | 0;
|
|
cy = morphY + morphRecord.controlDeltaY | 0;
|
|
morphX = cx + morphRecord.anchorDeltaX | 0;
|
|
morphY = cy + morphRecord.anchorDeltaY | 0;
|
|
} else {
|
|
deltaX = morphRecord.deltaX | 0;
|
|
deltaY = morphRecord.deltaY | 0;
|
|
cx = morphX + (deltaX >> 1);
|
|
cy = morphY + (deltaY >> 1);
|
|
morphX += deltaX;
|
|
morphY += deltaY;
|
|
}
|
|
segment.morphData.push(cx, cy, morphX, morphY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
applySegmentToStyles(segment, styles, linePaths, fillPaths, isMorph);
|
|
if (allPaths) {
|
|
push.apply(allPaths, fillPaths);
|
|
} else {
|
|
allPaths = fillPaths;
|
|
}
|
|
push.apply(allPaths, linePaths);
|
|
if (defaultPath) {
|
|
allPaths.push(defaultPath);
|
|
}
|
|
var removeCount = 0;
|
|
for (i = 0; i < allPaths.length; i++) {
|
|
path = allPaths[i];
|
|
if (!path.head()) {
|
|
removeCount++;
|
|
continue;
|
|
}
|
|
allPaths[i - removeCount] = segmentedPathToShapePath(path, isMorph, transferables);
|
|
}
|
|
allPaths.length -= removeCount;
|
|
return allPaths;
|
|
}
|
|
function segmentedPathToShapePath(path, isMorph, transferables) {
|
|
var start = path.head();
|
|
var end = start;
|
|
var finalRoot = null;
|
|
var finalHead = null;
|
|
var skippedMoves = 0;
|
|
var current = start.prev;
|
|
while (start) {
|
|
while (current) {
|
|
if (path.segmentsConnect(current, start)) {
|
|
if (current.next !== start) {
|
|
path.removeSegment(current);
|
|
path.insertSegment(current, start);
|
|
}
|
|
start = current;
|
|
current = start.prev;
|
|
skippedMoves++;
|
|
continue;
|
|
}
|
|
if (path.segmentsConnect(end, current)) {
|
|
path.removeSegment(current);
|
|
end.next = current;
|
|
current = current.prev;
|
|
end.next.prev = end;
|
|
end.next.next = null;
|
|
end = end.next;
|
|
skippedMoves++;
|
|
continue;
|
|
}
|
|
current = current.prev;
|
|
}
|
|
current = start.prev;
|
|
if (!finalRoot) {
|
|
finalRoot = start;
|
|
finalHead = end;
|
|
} else {
|
|
finalHead.next = start;
|
|
start.prev = finalHead;
|
|
finalHead = end;
|
|
finalHead.next = null;
|
|
}
|
|
if (!current) {
|
|
break;
|
|
}
|
|
start = end = current;
|
|
current = start.prev;
|
|
}
|
|
var totalCommandsLength = -skippedMoves;
|
|
var totalDataLength = -skippedMoves << 1;
|
|
current = finalRoot;
|
|
while (current) {
|
|
totalCommandsLength += current.commands.length;
|
|
totalDataLength += current.data.length;
|
|
current = current.next;
|
|
}
|
|
var shape = new ShapePath(path.fillStyle, path.lineStyle, totalCommandsLength, totalDataLength, isMorph, transferables);
|
|
var allCommands = shape.commands;
|
|
var allData = shape.data;
|
|
var allMorphData = shape.morphData;
|
|
var commandsIndex = 0;
|
|
var dataIndex = 0;
|
|
current = finalRoot;
|
|
while (current) {
|
|
var commands = current.commands;
|
|
var data = current.data;
|
|
var morphData = current.morphData;
|
|
var offset = +(data[0] === allData[dataIndex - 2] && data[1] === allData[dataIndex - 1]);
|
|
for (var i = offset; i < commands.length; i++, commandsIndex++) {
|
|
allCommands[commandsIndex] = commands[i];
|
|
}
|
|
for (i = offset << 1; i < data.length; i++, dataIndex++) {
|
|
allData[dataIndex] = data[i];
|
|
if (isMorph) {
|
|
allMorphData[dataIndex] = morphData[i];
|
|
}
|
|
}
|
|
current = current.next;
|
|
}
|
|
return shape;
|
|
}
|
|
var CAPS_STYLE_TYPES = [
|
|
'round',
|
|
'none',
|
|
'square'
|
|
];
|
|
var JOIN_STYLE_TYPES = [
|
|
'round',
|
|
'bevel',
|
|
'miter'
|
|
];
|
|
function processStyle(style, isLineStyle, dictionary, dependencies) {
|
|
if (isLineStyle) {
|
|
style.lineCap = CAPS_STYLE_TYPES[style.endCapStyle | 0];
|
|
style.lineJoin = JOIN_STYLE_TYPES[style.joinStyle | 0];
|
|
style.miterLimit = (style.miterLimitFactor || 1.5) * 2;
|
|
if (!style.color && style.hasFill) {
|
|
var fillStyle = processStyle(style.fillStyle, false, dictionary, dependencies);
|
|
style.style = fillStyle.style;
|
|
style.type = fillStyle.type;
|
|
style.transform = fillStyle.transform;
|
|
style.records = fillStyle.records;
|
|
style.focalPoint = fillStyle.focalPoint;
|
|
style.bitmapId = fillStyle.bitmapId;
|
|
style.repeat = fillStyle.repeat;
|
|
style.fillStyle = null;
|
|
return style;
|
|
}
|
|
}
|
|
var color;
|
|
if (style.type === undefined || style.type === GRAPHICS_FILL_SOLID) {
|
|
color = style.color;
|
|
style.style = 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + color.alpha / 255 + ')';
|
|
style.color = null;
|
|
return style;
|
|
}
|
|
var scale;
|
|
switch (style.type) {
|
|
case GRAPHICS_FILL_LINEAR_GRADIENT:
|
|
case GRAPHICS_FILL_RADIAL_GRADIENT:
|
|
case GRAPHICS_FILL_FOCAL_RADIAL_GRADIENT:
|
|
scale = 819.2;
|
|
break;
|
|
case GRAPHICS_FILL_REPEATING_BITMAP:
|
|
case GRAPHICS_FILL_CLIPPED_BITMAP:
|
|
case GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP:
|
|
case GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP:
|
|
if (dictionary[style.bitmapId]) {
|
|
dependencies.push(dictionary[style.bitmapId].id);
|
|
scale = 0.05;
|
|
}
|
|
break;
|
|
default:
|
|
fail('invalid fill style', 'shape');
|
|
}
|
|
if (!style.matrix) {
|
|
return style;
|
|
}
|
|
var matrix = style.matrix;
|
|
style.transform = {
|
|
a: matrix.a * scale,
|
|
b: matrix.b * scale,
|
|
c: matrix.c * scale,
|
|
d: matrix.d * scale,
|
|
e: matrix.tx,
|
|
f: matrix.ty
|
|
};
|
|
style.matrix = null;
|
|
return style;
|
|
}
|
|
function createPathsList(styles, isLineStyle, dictionary, dependencies) {
|
|
var paths = [];
|
|
for (var i = 0; i < styles.length; i++) {
|
|
var style = processStyle(styles[i], isLineStyle, dictionary, dependencies);
|
|
if (!isLineStyle) {
|
|
paths[i] = new SegmentedPath(style, null);
|
|
} else {
|
|
paths[i] = new SegmentedPath(null, style);
|
|
}
|
|
}
|
|
return paths;
|
|
}
|
|
function defineShape(tag, dictionary) {
|
|
var dependencies = [];
|
|
var transferables = [];
|
|
var fillPaths = createPathsList(tag.fillStyles, false, dictionary, dependencies);
|
|
var linePaths = createPathsList(tag.lineStyles, true, dictionary, dependencies);
|
|
var paths = convertRecordsToStyledPaths(tag.records, fillPaths, linePaths, dictionary, dependencies, tag.recordsMorph || null, transferables);
|
|
if (tag.bboxMorph) {
|
|
var mbox = tag.bboxMorph;
|
|
extendBoundsByPoint(tag.bbox, mbox.xMin, mbox.yMin);
|
|
extendBoundsByPoint(tag.bbox, mbox.xMax, mbox.yMax);
|
|
mbox = tag.strokeBboxMorph;
|
|
if (mbox) {
|
|
extendBoundsByPoint(tag.strokeBbox, mbox.xMin, mbox.yMin);
|
|
extendBoundsByPoint(tag.strokeBbox, mbox.xMax, mbox.yMax);
|
|
}
|
|
}
|
|
return {
|
|
type: 'shape',
|
|
id: tag.id,
|
|
strokeBbox: tag.strokeBbox,
|
|
strokeBboxMorph: tag.strokeBboxMorph,
|
|
bbox: tag.bbox,
|
|
bboxMorph: tag.bboxMorph,
|
|
isMorph: tag.isMorph,
|
|
paths: paths,
|
|
require: dependencies.length ? dependencies : null,
|
|
transferables: transferables
|
|
};
|
|
}
|
|
function logShape(paths, bbox) {
|
|
var output = '{"bounds":' + JSON.stringify(bbox) + ',"paths":[' + paths.map(function (path) {
|
|
return path.serialize();
|
|
}).join() + ']}';
|
|
console.log(output);
|
|
}
|
|
function SegmentedPath(fillStyle, lineStyle) {
|
|
this.fillStyle = fillStyle;
|
|
this.lineStyle = lineStyle;
|
|
this._head = null;
|
|
}
|
|
SegmentedPath.prototype = {
|
|
addSegment: function (commands, data, morphData) {
|
|
var segment = {
|
|
commands: commands,
|
|
data: data,
|
|
morphData: morphData,
|
|
prev: this._head,
|
|
next: null
|
|
};
|
|
if (this._head) {
|
|
this._head.next = segment;
|
|
}
|
|
this._head = segment;
|
|
return segment;
|
|
},
|
|
removeSegment: function (segment) {
|
|
if (segment.prev) {
|
|
segment.prev.next = segment.next;
|
|
}
|
|
if (segment.next) {
|
|
segment.next.prev = segment.prev;
|
|
}
|
|
},
|
|
insertSegment: function (segment, next) {
|
|
var prev = next.prev;
|
|
segment.prev = prev;
|
|
segment.next = next;
|
|
if (prev) {
|
|
prev.next = segment;
|
|
}
|
|
next.prev = segment;
|
|
},
|
|
head: function () {
|
|
return this._head;
|
|
},
|
|
segmentsConnect: function (first, second) {
|
|
var firstLength = first.data.length;
|
|
return first.data[firstLength - 2] === second.data[0] && first.data[firstLength - 1] === second.data[1];
|
|
}
|
|
};
|
|
var SHAPE_MOVE_TO = 1;
|
|
var SHAPE_LINE_TO = 2;
|
|
var SHAPE_CURVE_TO = 3;
|
|
var SHAPE_WIDE_MOVE_TO = 4;
|
|
var SHAPE_WIDE_LINE_TO = 5;
|
|
var SHAPE_CUBIC_CURVE_TO = 6;
|
|
var SHAPE_CIRCLE = 7;
|
|
var SHAPE_ELLIPSE = 8;
|
|
function ShapePath(fillStyle, lineStyle, commandsCount, dataLength, isMorph, transferables) {
|
|
this.fillStyle = fillStyle;
|
|
this.lineStyle = lineStyle;
|
|
if (commandsCount) {
|
|
this.commands = new Uint8Array(commandsCount);
|
|
this.data = new Int32Array(dataLength);
|
|
this.morphData = isMorph ? new Int32Array(dataLength) : null;
|
|
} else {
|
|
this.commands = [];
|
|
this.data = [];
|
|
}
|
|
this.bounds = null;
|
|
this.strokeBounds = null;
|
|
this.isMorph = !(!isMorph);
|
|
this.fullyInitialized = false;
|
|
if (inWorker) {
|
|
this.buffers = [
|
|
this.commands.buffer,
|
|
this.data.buffer
|
|
];
|
|
transferables.push(this.commands.buffer, this.data.buffer);
|
|
if (isMorph) {
|
|
this.buffers.push(this.morphData.buffer);
|
|
transferables.push(this.morphData.buffer);
|
|
}
|
|
} else {
|
|
this.buffers = null;
|
|
}
|
|
}
|
|
ShapePath.prototype = {
|
|
get isEmpty() {
|
|
return this.commands.length === 0;
|
|
},
|
|
moveTo: function (x, y) {
|
|
if (this.commands[this.commands.length - 1] === SHAPE_MOVE_TO) {
|
|
this.data[this.data.length - 2] = x;
|
|
this.data[this.data.length - 1] = y;
|
|
return;
|
|
}
|
|
this.commands.push(SHAPE_MOVE_TO);
|
|
this.data.push(x, y);
|
|
},
|
|
lineTo: function (x, y) {
|
|
this.commands.push(SHAPE_LINE_TO);
|
|
this.data.push(x, y);
|
|
},
|
|
curveTo: function (controlX, controlY, anchorX, anchorY) {
|
|
this.commands.push(SHAPE_CURVE_TO);
|
|
this.data.push(controlX, controlY, anchorX, anchorY);
|
|
},
|
|
cubicCurveTo: function (control1X, control1Y, control2X, control2Y, anchorX, anchorY) {
|
|
this.commands.push(SHAPE_CUBIC_CURVE_TO);
|
|
this.data.push(control1X, control1Y, control2X, control2Y, anchorX, anchorY);
|
|
},
|
|
rect: function (x, y, w, h) {
|
|
var x2 = x + w;
|
|
var y2 = y + h;
|
|
this.commands.push(SHAPE_MOVE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO, SHAPE_LINE_TO);
|
|
this.data.push(x, y, x2, y, x2, y2, x, y2, x, y);
|
|
},
|
|
circle: function (x, y, radius) {
|
|
this.commands.push(SHAPE_CIRCLE);
|
|
this.data.push(x, y, radius);
|
|
},
|
|
ellipse: function (x, y, radiusX, radiusY) {
|
|
this.commands.push(SHAPE_ELLIPSE);
|
|
this.data.push(x, y, radiusX, radiusY);
|
|
},
|
|
draw: function (ctx, clip, ratio, colorTransform) {
|
|
if (clip && !this.fillStyle) {
|
|
return;
|
|
}
|
|
ctx.beginPath();
|
|
var commands = this.commands;
|
|
var data = this.data;
|
|
var morphData = this.morphData;
|
|
var formOpen = false;
|
|
var formOpenX = 0;
|
|
var formOpenY = 0;
|
|
if (!this.isMorph) {
|
|
for (var j = 0, k = 0; j < commands.length; j++) {
|
|
switch (commands[j]) {
|
|
case SHAPE_MOVE_TO:
|
|
formOpen = true;
|
|
formOpenX = data[k++] / 20;
|
|
formOpenY = data[k++] / 20;
|
|
ctx.moveTo(formOpenX, formOpenY);
|
|
break;
|
|
case SHAPE_WIDE_MOVE_TO:
|
|
ctx.moveTo(data[k++] / 20, data[k++] / 20);
|
|
k += 2;
|
|
break;
|
|
case SHAPE_LINE_TO:
|
|
ctx.lineTo(data[k++] / 20, data[k++] / 20);
|
|
break;
|
|
case SHAPE_WIDE_LINE_TO:
|
|
ctx.lineTo(data[k++] / 20, data[k++] / 20);
|
|
k += 2;
|
|
break;
|
|
case SHAPE_CURVE_TO:
|
|
ctx.quadraticCurveTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20);
|
|
break;
|
|
case SHAPE_CUBIC_CURVE_TO:
|
|
ctx.bezierCurveTo(data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20, data[k++] / 20);
|
|
break;
|
|
case SHAPE_CIRCLE:
|
|
if (formOpen) {
|
|
ctx.lineTo(formOpenX, formOpenY);
|
|
formOpen = false;
|
|
}
|
|
ctx.moveTo((data[k] + data[k + 2]) / 20, data[k + 1] / 20);
|
|
ctx.arc(data[k++] / 20, data[k++] / 20, data[k++] / 20, 0, Math.PI * 2, false);
|
|
break;
|
|
case SHAPE_ELLIPSE:
|
|
if (formOpen) {
|
|
ctx.lineTo(formOpenX, formOpenY);
|
|
formOpen = false;
|
|
}
|
|
var x = data[k++];
|
|
var y = data[k++];
|
|
var rX = data[k++];
|
|
var rY = data[k++];
|
|
var radius;
|
|
if (rX !== rY) {
|
|
ctx.save();
|
|
var ellipseScale;
|
|
if (rX > rY) {
|
|
ellipseScale = rX / rY;
|
|
radius = rY;
|
|
x /= ellipseScale;
|
|
ctx.scale(ellipseScale, 1);
|
|
} else {
|
|
ellipseScale = rY / rX;
|
|
radius = rX;
|
|
y /= ellipseScale;
|
|
ctx.scale(1, ellipseScale);
|
|
}
|
|
}
|
|
ctx.moveTo((x + radius) / 20, y / 20);
|
|
ctx.arc(x / 20, y / 20, radius / 20, 0, Math.PI * 2, false);
|
|
if (rX !== rY) {
|
|
ctx.restore();
|
|
}
|
|
break;
|
|
default:
|
|
if (commands[j] === 0 && j === commands.length - 1) {
|
|
break;
|
|
}
|
|
console.warn('Unknown drawing command encountered: ' + commands[j]);
|
|
}
|
|
}
|
|
} else {
|
|
for (var j = 0, k = 0; j < commands.length; j++) {
|
|
switch (commands[j]) {
|
|
case SHAPE_MOVE_TO:
|
|
ctx.moveTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio));
|
|
break;
|
|
case SHAPE_LINE_TO:
|
|
ctx.lineTo(morph(data[k] / 20, morphData[k++] / 20, ratio), morph(data[k] / 20, morphData[k++] / 20, ratio));
|
|
break;
|
|
case SHAPE_CURVE_TO:
|
|
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));
|
|
break;
|
|
default:
|
|
console.warn('Drawing command not supported for morph shapes: ' + commands[j]);
|
|
}
|
|
}
|
|
}
|
|
if (!clip) {
|
|
var fillStyle = this.fillStyle;
|
|
if (fillStyle) {
|
|
colorTransform.setFillStyle(ctx, fillStyle.style);
|
|
ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = fillStyle.smooth;
|
|
var m = fillStyle.transform;
|
|
ctx.save();
|
|
colorTransform.setAlpha(ctx);
|
|
if (m) {
|
|
ctx.transform(m.a, m.b, m.c, m.d, m.e / 20, m.f / 20);
|
|
}
|
|
ctx.fill();
|
|
ctx.restore();
|
|
}
|
|
var lineStyle = this.lineStyle;
|
|
if (lineStyle) {
|
|
colorTransform.setStrokeStyle(ctx, lineStyle.style);
|
|
ctx.save();
|
|
colorTransform.setAlpha(ctx);
|
|
ctx.lineWidth = Math.max(lineStyle.width / 20, 1);
|
|
ctx.lineCap = lineStyle.lineCap;
|
|
ctx.lineJoin = lineStyle.lineJoin;
|
|
ctx.miterLimit = lineStyle.miterLimit;
|
|
ctx.stroke();
|
|
ctx.restore();
|
|
}
|
|
} else {
|
|
ctx.fill();
|
|
}
|
|
ctx.closePath();
|
|
},
|
|
isPointInPath: function (x, y) {
|
|
if (!(this.fillStyle || this.lineStyle)) {
|
|
return false;
|
|
}
|
|
var bounds = this.strokeBounds || this.bounds || this._calculateBounds();
|
|
if (x < bounds.xMin || x > bounds.xMax || y < bounds.yMin || y > bounds.yMax) {
|
|
return false;
|
|
}
|
|
if (this.fillStyle && this.isPointInFill(x, y)) {
|
|
return true;
|
|
}
|
|
return this.lineStyle && this.lineStyle.width !== undefined && this.isPointInStroke(x, y);
|
|
},
|
|
isPointInFill: function (x, y) {
|
|
var commands = this.commands;
|
|
var data = this.data;
|
|
var length = commands.length;
|
|
var inside = false;
|
|
var fromX = 0;
|
|
var fromY = 0;
|
|
var toX = 0;
|
|
var toY = 0;
|
|
var localX;
|
|
var localY;
|
|
var cpX;
|
|
var cpY;
|
|
var rX;
|
|
var rY;
|
|
var formOpen = false;
|
|
var formOpenX = 0;
|
|
var formOpenY = 0;
|
|
for (var commandIndex = 0, dataIndex = 0; commandIndex < length; commandIndex++) {
|
|
switch (commands[commandIndex]) {
|
|
case SHAPE_WIDE_MOVE_TO:
|
|
dataIndex += 2;
|
|
case SHAPE_MOVE_TO:
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
if (formOpen && intersectsLine(x, y, fromX, fromY, formOpenX, formOpenY)) {
|
|
inside = !inside;
|
|
}
|
|
formOpen = true;
|
|
formOpenX = toX;
|
|
formOpenY = toY;
|
|
break;
|
|
case SHAPE_WIDE_LINE_TO:
|
|
dataIndex += 2;
|
|
case SHAPE_LINE_TO:
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
if (intersectsLine(x, y, fromX, fromY, toX, toY)) {
|
|
inside = !inside;
|
|
}
|
|
break;
|
|
case SHAPE_CURVE_TO:
|
|
cpX = data[dataIndex++];
|
|
cpY = data[dataIndex++];
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
if (cpY > y === fromY > y && toY > y === fromY > y) {
|
|
break;
|
|
}
|
|
if (fromX >= x && cpX >= x && toX >= x) {
|
|
inside = !inside;
|
|
break;
|
|
}
|
|
var a = fromY - 2 * cpY + toY;
|
|
var c = fromY - y;
|
|
var b = 2 * (cpY - fromY);
|
|
var d = b * b - 4 * a * c;
|
|
if (d < 0) {
|
|
break;
|
|
}
|
|
d = Math.sqrt(d);
|
|
a = 1 / (a + a);
|
|
var t1 = (d - b) * a;
|
|
var t2 = (-b - d) * a;
|
|
if (t1 >= 0 && t1 <= 1 && quadraticBezier(fromX, cpX, toX, t1) > x) {
|
|
inside = !inside;
|
|
}
|
|
if (t2 >= 0 && t2 <= 1 && quadraticBezier(fromX, cpX, toX, t2) > x) {
|
|
inside = !inside;
|
|
}
|
|
break;
|
|
case SHAPE_CUBIC_CURVE_TO:
|
|
cpX = data[dataIndex++];
|
|
cpY = data[dataIndex++];
|
|
var cp2X = data[dataIndex++];
|
|
var cp2Y = data[dataIndex++];
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
if (cpY > y === fromY > y && cp2Y > y === fromY > y && toY > y === fromY > y) {
|
|
break;
|
|
}
|
|
if (fromX >= x && cpX >= x && cp2X >= x && toX >= x) {
|
|
inside = !inside;
|
|
break;
|
|
}
|
|
var roots = cubicXAtY(fromX, fromY, cpX, cpY, cp2X, cp2Y, toX, toY, y);
|
|
for (var i = roots.length; i--;) {
|
|
if (roots[i] >= x) {
|
|
inside = !inside;
|
|
}
|
|
}
|
|
break;
|
|
case SHAPE_CIRCLE:
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
var r = data[dataIndex++];
|
|
localX = x - toX;
|
|
localY = y - toY;
|
|
if (localX * localX + localY * localY < r * r) {
|
|
inside = !inside;
|
|
}
|
|
toX += r;
|
|
break;
|
|
case SHAPE_ELLIPSE:
|
|
cpX = data[dataIndex++];
|
|
cpY = data[dataIndex++];
|
|
rX = data[dataIndex++];
|
|
rY = data[dataIndex++];
|
|
localX = x - cpX;
|
|
localY = y - cpY;
|
|
if (localX * localX / (rX * rX) + localY * localY / (rY * rY) <= 1) {
|
|
inside = !inside;
|
|
}
|
|
toX = cpX + rX;
|
|
toY = cpY;
|
|
break;
|
|
default:
|
|
if (!inWorker) {
|
|
console.warn('Drawing command not handled in isPointInPath: ' + commands[commandIndex]);
|
|
}
|
|
}
|
|
fromX = toX;
|
|
fromY = toY;
|
|
}
|
|
if (formOpen && intersectsLine(x, y, fromX, fromY, formOpenX, formOpenY)) {
|
|
inside = !inside;
|
|
}
|
|
return inside;
|
|
},
|
|
isPointInStroke: function (x, y) {
|
|
var commands = this.commands;
|
|
var data = this.data;
|
|
var length = commands.length;
|
|
var width = this.lineStyle.width;
|
|
var halfWidth = width / 2;
|
|
var halfWidthSq = halfWidth * halfWidth;
|
|
var minX = x - halfWidth;
|
|
var maxX = x + halfWidth;
|
|
var minY = y - halfWidth;
|
|
var maxY = y + halfWidth;
|
|
var fromX = 0;
|
|
var fromY = 0;
|
|
var toX = 0;
|
|
var toY = 0;
|
|
var localX;
|
|
var localY;
|
|
var cpX;
|
|
var cpY;
|
|
var rX;
|
|
var rY;
|
|
var curveX;
|
|
var curveY;
|
|
var t;
|
|
for (var commandIndex = 0, dataIndex = 0; commandIndex < length; commandIndex++) {
|
|
switch (commands[commandIndex]) {
|
|
case SHAPE_WIDE_MOVE_TO:
|
|
dataIndex += 2;
|
|
case SHAPE_MOVE_TO:
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
break;
|
|
case SHAPE_WIDE_LINE_TO:
|
|
dataIndex += 2;
|
|
case SHAPE_LINE_TO:
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
if (fromX === toX && fromY === toY) {
|
|
break;
|
|
}
|
|
if (maxX < fromX && maxX < toX || minX > fromX && minX > toX || maxY < fromY && maxY < toY || minY > fromY && minY > toY) {
|
|
break;
|
|
}
|
|
if (toX === fromX || toY === fromY) {
|
|
return true;
|
|
}
|
|
t = ((x - fromX) * (toX - fromX) + (y - fromY) * (toY - fromY)) / distanceSq(fromX, fromY, toX, toY);
|
|
if (t < 0) {
|
|
if (distanceSq(x, y, fromX, fromY) <= halfWidthSq) {
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
if (t > 1) {
|
|
if (distanceSq(x, y, toX, toY) <= halfWidthSq) {
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
if (distanceSq(x, y, fromX + t * (toX - fromX), fromY + t * (toY - fromY)) <= halfWidthSq) {
|
|
return true;
|
|
}
|
|
break;
|
|
case SHAPE_CURVE_TO:
|
|
cpX = data[dataIndex++];
|
|
cpY = data[dataIndex++];
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
var extremeX = quadraticBezierExtreme(fromX, cpX, toX);
|
|
if (maxX < fromX && maxX < extremeX && maxX < toX || minX > fromX && minX > extremeX && minX > toX) {
|
|
break;
|
|
}
|
|
var extremeY = quadraticBezierExtreme(fromY, cpY, toY);
|
|
if (maxY < fromY && maxY < extremeY && maxY < toY || minY > fromY && minY > extremeY && minY > toY) {
|
|
break;
|
|
}
|
|
for (t = 0; t < 1; t += 0.02) {
|
|
curveX = quadraticBezier(fromX, cpX, toX, t);
|
|
if (curveX < minX || curveX > maxX) {
|
|
continue;
|
|
}
|
|
curveY = quadraticBezier(fromY, cpY, toY, t);
|
|
if (curveY < minY || curveY > maxY) {
|
|
continue;
|
|
}
|
|
if ((x - curveX) * (x - curveX) + (y - curveY) * (y - curveY) < halfWidthSq) {
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
case SHAPE_CUBIC_CURVE_TO:
|
|
cpX = data[dataIndex++];
|
|
cpY = data[dataIndex++];
|
|
var cp2X = data[dataIndex++];
|
|
var cp2Y = data[dataIndex++];
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
var extremesX = cubicBezierExtremes(fromX, cpX, cp2X, toX);
|
|
while (extremesX.length < 2) {
|
|
extremesX.push(toX);
|
|
}
|
|
if (maxX < fromX && maxX < toX && maxX < extremesX[0] && maxX < extremesX[1] || minX > fromX && minX > toX && minX > extremesX[0] && minX > extremesX[1]) {
|
|
break;
|
|
}
|
|
var extremesY = cubicBezierExtremes(fromY, cpY, cp2Y, toY);
|
|
while (extremesY.length < 2) {
|
|
extremesY.push(toY);
|
|
}
|
|
if (maxY < fromY && maxY < toY && maxY < extremesY[0] && maxY < extremesY[1] || minY > fromY && minY > toY && minY > extremesY[0] && minY > extremesY[1]) {
|
|
break;
|
|
}
|
|
for (t = 0; t < 1; t += 0.02) {
|
|
curveX = cubicBezier(fromX, cpX, cp2X, toX, t);
|
|
if (curveX < minX || curveX > maxX) {
|
|
continue;
|
|
}
|
|
curveY = cubicBezier(fromY, cpY, cp2Y, toY, t);
|
|
if (curveY < minY || curveY > maxY) {
|
|
continue;
|
|
}
|
|
if ((x - curveX) * (x - curveX) + (y - curveY) * (y - curveY) < halfWidthSq) {
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
case SHAPE_CIRCLE:
|
|
cpX = data[dataIndex++];
|
|
cpY = data[dataIndex++];
|
|
var r = data[dataIndex++];
|
|
toX = cpX + r;
|
|
toY = cpY;
|
|
if (maxX < cpX - r || minX > cpX + r || maxY < cpY - r || minY > cpY + r) {
|
|
break;
|
|
}
|
|
localX = x - cpX;
|
|
localY = y - cpY;
|
|
var rMin = r - halfWidth;
|
|
var rMax = r + halfWidth;
|
|
var distSq = localX * localX + localY * localY;
|
|
if (distSq >= rMin * rMin && distSq <= rMax * rMax) {
|
|
return true;
|
|
}
|
|
break;
|
|
case SHAPE_ELLIPSE:
|
|
cpX = data[dataIndex++];
|
|
cpY = data[dataIndex++];
|
|
rX = data[dataIndex++];
|
|
rY = data[dataIndex++];
|
|
toX = cpX + rX;
|
|
toY = cpY;
|
|
localX = Math.abs(x - cpX);
|
|
localY = Math.abs(y - cpY);
|
|
localX -= halfWidth;
|
|
localY -= halfWidth;
|
|
if (localX * localX / (rX * rX) + localY * localY / (rY * rY) > 1) {
|
|
break;
|
|
}
|
|
localX += width;
|
|
localY += width;
|
|
if (localX * localX / (rX * rX) + localY * localY / (rY * rY) > 1) {
|
|
return true;
|
|
}
|
|
break;
|
|
default:
|
|
if (!inWorker) {
|
|
console.warn('Drawing command not handled in isPointInPath: ' + commands[commandIndex]);
|
|
}
|
|
}
|
|
fromX = toX;
|
|
fromY = toY;
|
|
}
|
|
return false;
|
|
},
|
|
getBounds: function (includeStroke) {
|
|
var bounds = includeStroke ? this.strokeBounds : this.bounds;
|
|
if (!bounds) {
|
|
this._calculateBounds();
|
|
bounds = includeStroke ? this.strokeBounds : this.bounds;
|
|
}
|
|
return bounds;
|
|
},
|
|
_calculateBounds: function () {
|
|
var commands = this.commands;
|
|
var data = this.data;
|
|
var length = commands.length;
|
|
var bounds;
|
|
if (commands[0] === SHAPE_MOVE_TO || commands[0] > SHAPE_CUBIC_CURVE_TO) {
|
|
bounds = {
|
|
xMin: data[0],
|
|
yMin: data[1]
|
|
};
|
|
} else {
|
|
bounds = {
|
|
xMin: 0,
|
|
yMin: 0
|
|
};
|
|
}
|
|
bounds.xMax = bounds.xMin;
|
|
bounds.yMax = bounds.yMin;
|
|
var fromX = bounds.xMin;
|
|
var fromY = bounds.yMin;
|
|
for (var commandIndex = 0, dataIndex = 0; commandIndex < length; commandIndex++) {
|
|
var toX;
|
|
var toY;
|
|
var cpX;
|
|
var cpY;
|
|
switch (commands[commandIndex]) {
|
|
case SHAPE_WIDE_MOVE_TO:
|
|
dataIndex += 2;
|
|
case SHAPE_MOVE_TO:
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
extendBoundsByPoint(bounds, toX, toY);
|
|
break;
|
|
case SHAPE_WIDE_LINE_TO:
|
|
dataIndex += 2;
|
|
case SHAPE_LINE_TO:
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
extendBoundsByPoint(bounds, toX, toY);
|
|
break;
|
|
case SHAPE_CURVE_TO:
|
|
cpX = data[dataIndex++];
|
|
cpY = data[dataIndex++];
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
extendBoundsByPoint(bounds, toX, toY);
|
|
if (cpX < fromX || cpX > toX) {
|
|
extendBoundsByX(bounds, quadraticBezierExtreme(fromX, cpX, toX));
|
|
}
|
|
if (cpY < fromY || cpY > toY) {
|
|
extendBoundsByY(bounds, quadraticBezierExtreme(fromY, cpY, toY));
|
|
}
|
|
break;
|
|
case SHAPE_CUBIC_CURVE_TO:
|
|
cpX = data[dataIndex++];
|
|
cpY = data[dataIndex++];
|
|
var cp2X = data[dataIndex++];
|
|
var cp2Y = data[dataIndex++];
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
extendBoundsByPoint(bounds, toX, toY);
|
|
var extremes;
|
|
var i;
|
|
if (cpX < fromX || cp2X < fromX || cpX > toX || cp2X > toX) {
|
|
extremes = cubicBezierExtremes(fromX, cpX, cp2X, toX);
|
|
for (i = extremes.length; i--;) {
|
|
extendBoundsByX(bounds, extremes[i]);
|
|
}
|
|
}
|
|
if (cpY < fromY || cp2Y < fromY || cpY > toY || cp2Y > toY) {
|
|
extremes = cubicBezierExtremes(fromY, cpY, cp2Y, toY);
|
|
for (i = extremes.length; i--;) {
|
|
extendBoundsByY(bounds, extremes[i]);
|
|
}
|
|
}
|
|
break;
|
|
case SHAPE_CIRCLE:
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
var radius = data[dataIndex++];
|
|
extendBoundsByPoint(bounds, toX - radius, toY - radius);
|
|
extendBoundsByPoint(bounds, toX + radius, toY + radius);
|
|
toX += radius;
|
|
break;
|
|
case SHAPE_ELLIPSE:
|
|
toX = data[dataIndex++];
|
|
toY = data[dataIndex++];
|
|
var radiusX = data[dataIndex++];
|
|
var radiusY = data[dataIndex++];
|
|
extendBoundsByPoint(bounds, toX - radiusX, toY - radiusY);
|
|
extendBoundsByPoint(bounds, toX + radiusX, toY + radiusY);
|
|
toX += radiusX;
|
|
break;
|
|
default:
|
|
if (!inWorker) {
|
|
console.warn('Drawing command not handled in bounds calculation: ' + commands[commandIndex]);
|
|
}
|
|
}
|
|
fromX = toX;
|
|
fromY = toY;
|
|
}
|
|
this.bounds = bounds;
|
|
if (this.lineStyle) {
|
|
var halfLineWidth = this.lineStyle.width / 2;
|
|
this.strokeBounds = {
|
|
xMin: bounds.xMin - halfLineWidth,
|
|
yMin: bounds.yMin - halfLineWidth,
|
|
xMax: bounds.xMax + halfLineWidth,
|
|
yMax: bounds.yMax + halfLineWidth
|
|
};
|
|
return this.strokeBounds;
|
|
} else {
|
|
this.strokeBounds = bounds;
|
|
}
|
|
return bounds;
|
|
},
|
|
serialize: function () {
|
|
var output = '{';
|
|
if (this.fillStyle) {
|
|
output += '"fill":' + JSON.stringify(this.fillStyle) + ',';
|
|
}
|
|
if (this.lineStyle) {
|
|
output += '"stroke":' + JSON.stringify(this.lineStyle) + ',';
|
|
}
|
|
output += '"commands":[' + Array.apply([], this.commands).join() + '],';
|
|
output += '"data":[' + Array.apply([], this.data).join() + ']';
|
|
return output + '}';
|
|
}
|
|
};
|
|
ShapePath.fromPlainObject = function (obj) {
|
|
var path = new ShapePath(obj.fill || null, obj.stroke || null);
|
|
path.commands = new Uint8Array(obj.commands);
|
|
path.data = new Int32Array(obj.data);
|
|
if (!inWorker) {
|
|
finishShapePath(path);
|
|
}
|
|
return path;
|
|
};
|
|
function distanceSq(x1, y1, x2, y2) {
|
|
var dX = x2 - x1;
|
|
var dY = y2 - y1;
|
|
return dX * dX + dY * dY;
|
|
}
|
|
function intersectsLine(x, y, x1, y1, x2, y2) {
|
|
return y2 > y !== y1 > y && x < (x1 - x2) * (y - y2) / (y1 - y2) + x2;
|
|
}
|
|
function quadraticBezier(from, cp, to, t) {
|
|
var inverseT = 1 - t;
|
|
return from * inverseT * inverseT + 2 * cp * inverseT * t + to * t * t;
|
|
}
|
|
function quadraticBezierExtreme(from, cp, to) {
|
|
var t = (from - cp) / (from - 2 * cp + to);
|
|
if (t < 0) {
|
|
return from;
|
|
}
|
|
if (t > 1) {
|
|
return to;
|
|
}
|
|
return quadraticBezier(from, cp, to, t);
|
|
}
|
|
function cubicBezier(from, cp, cp2, to, t) {
|
|
var tSq = t * t;
|
|
var inverseT = 1 - t;
|
|
var inverseTSq = inverseT * inverseT;
|
|
return from * inverseT * inverseTSq + 3 * cp * t * inverseTSq + 3 * cp2 * inverseT * tSq + to * t * tSq;
|
|
}
|
|
function cubicBezierExtremes(from, cp, cp2, to) {
|
|
var d1 = cp - from;
|
|
var d2 = cp2 - cp;
|
|
d2 *= 2;
|
|
var d3 = to - cp2;
|
|
if (d1 + d3 === d2) {
|
|
d3 *= 1.0001;
|
|
}
|
|
var fHead = 2 * d1 - d2;
|
|
var part1 = d2 - 2 * d1;
|
|
var fCenter = Math.sqrt(part1 * part1 - 4 * d1 * (d1 - d2 + d3));
|
|
var fTail = 2 * (d1 - d2 + d3);
|
|
var t1 = (fHead + fCenter) / fTail;
|
|
var t2 = (fHead - fCenter) / fTail;
|
|
var result = [];
|
|
if (t1 >= 0 && t1 <= 1) {
|
|
result.push(cubicBezier(from, cp, cp2, to, t1));
|
|
}
|
|
if (t2 >= 0 && t2 <= 1) {
|
|
result.push(cubicBezier(from, cp, cp2, to, t2));
|
|
}
|
|
return result;
|
|
}
|
|
function cubicXAtY(x0, y0, cx, cy, cx1, cy1, x1, y1, y) {
|
|
var dX = 3 * (cx - x0);
|
|
var dY = 3 * (cy - y0);
|
|
var bX = 3 * (cx1 - cx) - dX;
|
|
var bY = 3 * (cy1 - cy) - dY;
|
|
var c3X = x1 - x0 - dX - bX;
|
|
var c3Y = y1 - y0 - dY - bY;
|
|
function f(t) {
|
|
return t * (dY + t * (bY + t * c3Y)) + y0 - y;
|
|
}
|
|
function pointAt(t) {
|
|
if (t < 0) {
|
|
t = 0;
|
|
} else if (t > 1) {
|
|
t = 1;
|
|
}
|
|
return x0 + t * (dX + t * (bX + t * c3X));
|
|
}
|
|
function bisectCubicBezierRange(f, l, r, limit) {
|
|
if (Math.abs(r - l) <= limit) {
|
|
return;
|
|
}
|
|
var middle = 0.5 * (l + r);
|
|
if (f(l) * f(r) <= 0) {
|
|
left = l;
|
|
right = r;
|
|
return;
|
|
}
|
|
bisectCubicBezierRange(f, l, middle, limit);
|
|
bisectCubicBezierRange(f, middle, r, limit);
|
|
}
|
|
var left = 0;
|
|
var right = 1;
|
|
bisectCubicBezierRange(f, 0, 1, 0.05);
|
|
var t0 = findRoot(left, right, f, 50, 0.000001);
|
|
var evalResult = Math.abs(f(t0));
|
|
if (evalResult > 0.00001) {
|
|
return [];
|
|
}
|
|
var result = [];
|
|
if (t0 <= 1) {
|
|
result.push(pointAt(t0));
|
|
}
|
|
var a = c3Y;
|
|
var b = t0 * a + bY;
|
|
var c = t0 * b + dY;
|
|
var d = b * b - 4 * a * c;
|
|
if (d < 0) {
|
|
return result;
|
|
}
|
|
d = Math.sqrt(d);
|
|
a = 1 / (a + a);
|
|
var t1 = (d - b) * a;
|
|
var t2 = (-b - d) * a;
|
|
if (t1 >= 0 && t1 <= 1) {
|
|
result.push(pointAt(t1));
|
|
}
|
|
if (t2 >= 0 && t2 <= 1) {
|
|
result.push(pointAt(t2));
|
|
}
|
|
return result;
|
|
}
|
|
function findRoot(x0, x2, f, maxIterations, epsilon) {
|
|
var x1;
|
|
var y0;
|
|
var y1;
|
|
var y2;
|
|
var b;
|
|
var c;
|
|
var y10;
|
|
var y20;
|
|
var y21;
|
|
var xm;
|
|
var ym;
|
|
var temp;
|
|
var xmlast = x0;
|
|
y0 = f(x0);
|
|
if (y0 === 0) {
|
|
return x0;
|
|
}
|
|
y2 = f(x2);
|
|
if (y2 === 0) {
|
|
return x2;
|
|
}
|
|
if (y2 * y0 > 0) {
|
|
return x0;
|
|
}
|
|
var __iter = 0;
|
|
for (var i = 0; i < maxIterations; ++i) {
|
|
__iter++;
|
|
x1 = 0.5 * (x2 + x0);
|
|
y1 = f(x1);
|
|
if (y1 === 0) {
|
|
return x1;
|
|
}
|
|
if (Math.abs(x1 - x0) < epsilon) {
|
|
return x1;
|
|
}
|
|
if (y1 * y0 > 0) {
|
|
temp = x0;
|
|
x0 = x2;
|
|
x2 = temp;
|
|
temp = y0;
|
|
y0 = y2;
|
|
y2 = temp;
|
|
}
|
|
y10 = y1 - y0;
|
|
y21 = y2 - y1;
|
|
y20 = y2 - y0;
|
|
if (y2 * y20 < 2 * y1 * y10) {
|
|
x2 = x1;
|
|
y2 = y1;
|
|
} else {
|
|
b = (x1 - x0) / y10;
|
|
c = (y10 - y21) / (y21 * y20);
|
|
xm = x0 - b * y0 * (1 - c * y1);
|
|
ym = f(xm);
|
|
if (ym === 0) {
|
|
return xm;
|
|
}
|
|
if (Math.abs(xm - xmlast) < epsilon) {
|
|
return xm;
|
|
}
|
|
xmlast = xm;
|
|
if (ym * y0 < 0) {
|
|
x2 = xm;
|
|
y2 = ym;
|
|
} else {
|
|
x0 = xm;
|
|
y0 = ym;
|
|
x2 = x1;
|
|
y2 = y1;
|
|
}
|
|
}
|
|
}
|
|
return x1;
|
|
}
|
|
function extendBoundsByPoint(bounds, x, y) {
|
|
if (x < bounds.xMin) {
|
|
bounds.xMin = x;
|
|
} else if (x > bounds.xMax) {
|
|
bounds.xMax = x;
|
|
}
|
|
if (y < bounds.yMin) {
|
|
bounds.yMin = y;
|
|
} else if (y > bounds.yMax) {
|
|
bounds.yMax = y;
|
|
}
|
|
}
|
|
function extendBoundsByX(bounds, x) {
|
|
if (x < bounds.xMin) {
|
|
bounds.xMin = x;
|
|
} else if (x > bounds.xMax) {
|
|
bounds.xMax = x;
|
|
}
|
|
}
|
|
function extendBoundsByY(bounds, y) {
|
|
if (y < bounds.yMin) {
|
|
bounds.yMin = y;
|
|
} else if (y > bounds.yMax) {
|
|
bounds.yMax = y;
|
|
}
|
|
}
|
|
function morph(start, end, ratio) {
|
|
return start + (end - start) * ratio;
|
|
}
|
|
function finishShapePath(path, dictionaryResolved) {
|
|
if (path.fullyInitialized) {
|
|
return path;
|
|
}
|
|
if (!(path instanceof ShapePath)) {
|
|
var untypedPath = path;
|
|
path = new ShapePath(path.fillStyle, path.lineStyle, 0, 0, path.isMorph);
|
|
path.commands = new Uint8Array(untypedPath.buffers[0]);
|
|
path.data = new Int32Array(untypedPath.buffers[1]);
|
|
if (untypedPath.isMorph) {
|
|
path.morphData = new Int32Array(untypedPath.buffers[2]);
|
|
}
|
|
path.buffers = null;
|
|
}
|
|
path.fillStyle && initStyle(path.fillStyle, dictionaryResolved);
|
|
path.lineStyle && initStyle(path.lineStyle, dictionaryResolved);
|
|
path.fullyInitialized = true;
|
|
return path;
|
|
}
|
|
var inWorker = typeof window === 'undefined';
|
|
var factoryCtx = !inWorker ? document.createElement('canvas').getContext('2d') : null;
|
|
function buildLinearGradientFactory(colorStops) {
|
|
var defaultGradient = factoryCtx.createLinearGradient(-1, 0, 1, 0);
|
|
for (var i = 0; i < colorStops.length; i++) {
|
|
defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color);
|
|
}
|
|
var fn = function createLinearGradient(ctx, colorTransform) {
|
|
var gradient = ctx.createLinearGradient(-1, 0, 1, 0);
|
|
for (var i = 0; i < colorStops.length; i++) {
|
|
colorTransform.addGradientColorStop(gradient, colorStops[i].ratio, colorStops[i].color);
|
|
}
|
|
return gradient;
|
|
};
|
|
fn.defaultFillStyle = defaultGradient;
|
|
return fn;
|
|
}
|
|
function buildRadialGradientFactory(focalPoint, colorStops) {
|
|
var defaultGradient = factoryCtx.createRadialGradient(focalPoint, 0, 0, 0, 0, 1);
|
|
for (var i = 0; i < colorStops.length; i++) {
|
|
defaultGradient.addColorStop(colorStops[i].ratio, colorStops[i].color);
|
|
}
|
|
var fn = function createRadialGradient(ctx, colorTransform) {
|
|
var gradient = ctx.createRadialGradient(focalPoint, 0, 0, 0, 0, 1);
|
|
for (var i = 0; i < colorStops.length; i++) {
|
|
colorTransform.addGradientColorStop(gradient, colorStops[i].ratio, colorStops[i].color);
|
|
}
|
|
return gradient;
|
|
};
|
|
fn.defaultFillStyle = defaultGradient;
|
|
return fn;
|
|
}
|
|
function buildBitmapPatternFactory(img, repeat) {
|
|
var defaultPattern = factoryCtx.createPattern(img, repeat);
|
|
var cachedTransform, cachedTransformKey;
|
|
var fn = function createBitmapPattern(ctx, colorTransform) {
|
|
if (!colorTransform.mode) {
|
|
return defaultPattern;
|
|
}
|
|
var key = colorTransform.getTransformFingerprint();
|
|
if (key === cachedTransformKey) {
|
|
return cachedTransform;
|
|
}
|
|
var canvas = document.createElement('canvas');
|
|
canvas.width = img.width;
|
|
canvas.height = img.height;
|
|
var ctx = canvas.getContext('2d');
|
|
colorTransform.setAlpha(ctx, true);
|
|
ctx.drawImage(img, 0, 0);
|
|
cachedTransform = ctx.createPattern(canvas, repeat);
|
|
cachedTransformKey = key;
|
|
return cachedTransform;
|
|
};
|
|
fn.defaultFillStyle = defaultPattern;
|
|
return fn;
|
|
}
|
|
function initStyle(style, dictionaryResolved) {
|
|
if (style.type === undefined) {
|
|
return;
|
|
}
|
|
switch (style.type) {
|
|
case GRAPHICS_FILL_SOLID:
|
|
break;
|
|
case GRAPHICS_FILL_LINEAR_GRADIENT:
|
|
case GRAPHICS_FILL_RADIAL_GRADIENT:
|
|
case GRAPHICS_FILL_FOCAL_RADIAL_GRADIENT:
|
|
var records = style.records, colorStops = [];
|
|
for (var j = 0, n = records.length; j < n; j++) {
|
|
var record = records[j];
|
|
var colorStr = rgbaObjToStr(record.color);
|
|
colorStops.push({
|
|
ratio: record.ratio / 255,
|
|
color: colorStr
|
|
});
|
|
}
|
|
var gradientConstructor;
|
|
var isLinear = style.type === GRAPHICS_FILL_LINEAR_GRADIENT;
|
|
if (isLinear) {
|
|
gradientConstructor = buildLinearGradientFactory(colorStops);
|
|
} else {
|
|
gradientConstructor = buildRadialGradientFactory((style.focalPoint | 0) / 20, colorStops);
|
|
}
|
|
style.style = gradientConstructor;
|
|
break;
|
|
case GRAPHICS_FILL_REPEATING_BITMAP:
|
|
case GRAPHICS_FILL_CLIPPED_BITMAP:
|
|
case GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP:
|
|
case GRAPHICS_FILL_NONSMOOTHED_CLIPPED_BITMAP:
|
|
var bitmap = dictionaryResolved[style.bitmapId];
|
|
var repeat = style.type === GRAPHICS_FILL_REPEATING_BITMAP || style.type === GRAPHICS_FILL_NONSMOOTHED_REPEATING_BITMAP;
|
|
style.style = buildBitmapPatternFactory(bitmap.props.img, repeat ? 'repeat' : 'no-repeat');
|
|
break;
|
|
default:
|
|
fail('invalid fill style', 'shape');
|
|
}
|
|
}
|
|
var SOUND_SIZE_8_BIT = 0;
|
|
var SOUND_SIZE_16_BIT = 1;
|
|
var SOUND_TYPE_MONO = 0;
|
|
var SOUND_TYPE_STEREO = 1;
|
|
var SOUND_FORMAT_PCM_BE = 0;
|
|
var SOUND_FORMAT_ADPCM = 1;
|
|
var SOUND_FORMAT_MP3 = 2;
|
|
var SOUND_FORMAT_PCM_LE = 3;
|
|
var SOUND_FORMAT_NELLYMOSER_16 = 4;
|
|
var SOUND_FORMAT_NELLYMOSER_8 = 5;
|
|
var SOUND_FORMAT_NELLYMOSER = 6;
|
|
var SOUND_FORMAT_SPEEX = 11;
|
|
var SOUND_RATES = [
|
|
5512,
|
|
11250,
|
|
22500,
|
|
44100
|
|
];
|
|
var WaveHeader = new Uint8Array([
|
|
82,
|
|
73,
|
|
70,
|
|
70,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
87,
|
|
65,
|
|
86,
|
|
69,
|
|
102,
|
|
109,
|
|
116,
|
|
32,
|
|
16,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
0,
|
|
2,
|
|
0,
|
|
68,
|
|
172,
|
|
0,
|
|
0,
|
|
16,
|
|
177,
|
|
2,
|
|
0,
|
|
4,
|
|
0,
|
|
16,
|
|
0,
|
|
100,
|
|
97,
|
|
116,
|
|
97,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
]);
|
|
function packageWave(data, sampleRate, channels, size, swapBytes) {
|
|
var sizeInBytes = size >> 3;
|
|
var sizePerSecond = channels * sampleRate * sizeInBytes;
|
|
var sizePerSample = channels * sizeInBytes;
|
|
var dataLength = data.length + (data.length & 1);
|
|
var buffer = new ArrayBuffer(WaveHeader.length + dataLength);
|
|
var bytes = new Uint8Array(buffer);
|
|
bytes.set(WaveHeader);
|
|
if (swapBytes) {
|
|
for (var i = 0, j = WaveHeader.length; i < data.length; i += 2, j += 2) {
|
|
bytes[j] = data[i + 1];
|
|
bytes[j + 1] = data[i];
|
|
}
|
|
} else {
|
|
bytes.set(data, WaveHeader.length);
|
|
}
|
|
var view = new DataView(buffer);
|
|
view.setUint32(4, dataLength + 36, true);
|
|
view.setUint16(22, channels, true);
|
|
view.setUint32(24, sampleRate, true);
|
|
view.setUint32(28, sizePerSecond, true);
|
|
view.setUint16(32, sizePerSample, true);
|
|
view.setUint16(34, size, true);
|
|
view.setUint32(40, dataLength, true);
|
|
return {
|
|
data: bytes,
|
|
mimeType: 'audio/wav'
|
|
};
|
|
}
|
|
function defineSound(tag, dictionary) {
|
|
var channels = tag.soundType == SOUND_TYPE_STEREO ? 2 : 1;
|
|
var samplesCount = tag.samplesCount;
|
|
var sampleRate = SOUND_RATES[tag.soundRate];
|
|
var data = tag.soundData;
|
|
var pcm, packaged;
|
|
switch (tag.soundFormat) {
|
|
case SOUND_FORMAT_PCM_BE:
|
|
pcm = new Float32Array(samplesCount * channels);
|
|
if (tag.soundSize == SOUND_SIZE_16_BIT) {
|
|
for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
|
|
pcm[i] = (data[j] << 24 | data[j + 1] << 16) / 2147483648;
|
|
packaged = packageWave(data, sampleRate, channels, 16, true);
|
|
} else {
|
|
for (var i = 0; i < pcm.length; i++)
|
|
pcm[i] = (data[i] - 128) / 128;
|
|
packaged = packageWave(data, sampleRate, channels, 8, false);
|
|
}
|
|
break;
|
|
case SOUND_FORMAT_PCM_LE:
|
|
pcm = new Float32Array(samplesCount * channels);
|
|
if (tag.soundSize == SOUND_SIZE_16_BIT) {
|
|
for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
|
|
pcm[i] = (data[j + 1] << 24 | data[j] << 16) / 2147483648;
|
|
packaged = packageWave(data, sampleRate, channels, 16, false);
|
|
} else {
|
|
for (var i = 0; i < pcm.length; i++)
|
|
pcm[i] = (data[i] - 128) / 128;
|
|
packaged = packageWave(data, sampleRate, channels, 8, false);
|
|
}
|
|
break;
|
|
case SOUND_FORMAT_MP3:
|
|
packaged = {
|
|
data: new Uint8Array(data.subarray(2)),
|
|
mimeType: 'audio/mpeg'
|
|
};
|
|
break;
|
|
case SOUND_FORMAT_ADPCM:
|
|
var pcm16 = new Int16Array(samplesCount * channels);
|
|
decodeACPCMSoundData(data, pcm16, channels);
|
|
pcm = new Float32Array(samplesCount * channels);
|
|
for (var i = 0; i < pcm.length; i++)
|
|
pcm[i] = pcm16[i] / 32768;
|
|
packaged = packageWave(new Uint8Array(pcm16.buffer), sampleRate, channels, 16, !new Uint8Array(new Uint16Array([
|
|
1
|
|
]).buffer)[0]);
|
|
break;
|
|
default:
|
|
throw new Error('Unsupported audio format: ' + tag.soundFormat);
|
|
}
|
|
var sound = {
|
|
type: 'sound',
|
|
id: tag.id,
|
|
sampleRate: sampleRate,
|
|
channels: channels,
|
|
pcm: pcm
|
|
};
|
|
if (packaged)
|
|
sound.packaged = packaged;
|
|
return sound;
|
|
}
|
|
var ACPCMIndexTables = [
|
|
[
|
|
-1,
|
|
2
|
|
],
|
|
[
|
|
-1,
|
|
-1,
|
|
2,
|
|
4
|
|
],
|
|
[
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
2,
|
|
4,
|
|
6,
|
|
8
|
|
],
|
|
[
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
1,
|
|
2,
|
|
4,
|
|
6,
|
|
8,
|
|
10,
|
|
13,
|
|
16
|
|
]
|
|
];
|
|
var ACPCMStepSizeTable = [
|
|
7,
|
|
8,
|
|
9,
|
|
10,
|
|
11,
|
|
12,
|
|
13,
|
|
14,
|
|
16,
|
|
17,
|
|
19,
|
|
21,
|
|
23,
|
|
25,
|
|
28,
|
|
31,
|
|
34,
|
|
37,
|
|
41,
|
|
45,
|
|
50,
|
|
55,
|
|
60,
|
|
66,
|
|
73,
|
|
80,
|
|
88,
|
|
97,
|
|
107,
|
|
118,
|
|
130,
|
|
143,
|
|
157,
|
|
173,
|
|
190,
|
|
209,
|
|
230,
|
|
253,
|
|
279,
|
|
307,
|
|
337,
|
|
371,
|
|
408,
|
|
449,
|
|
494,
|
|
544,
|
|
598,
|
|
658,
|
|
724,
|
|
796,
|
|
876,
|
|
963,
|
|
1060,
|
|
1166,
|
|
1282,
|
|
1411,
|
|
1552,
|
|
1707,
|
|
1878,
|
|
2066,
|
|
2272,
|
|
2499,
|
|
2749,
|
|
3024,
|
|
3327,
|
|
3660,
|
|
4026,
|
|
4428,
|
|
4871,
|
|
5358,
|
|
5894,
|
|
6484,
|
|
7132,
|
|
7845,
|
|
8630,
|
|
9493,
|
|
10442,
|
|
11487,
|
|
12635,
|
|
13899,
|
|
15289,
|
|
16818,
|
|
18500,
|
|
20350,
|
|
22385,
|
|
24623,
|
|
27086,
|
|
29794,
|
|
32767
|
|
];
|
|
function decodeACPCMSoundData(data, pcm16, channels) {
|
|
function readBits(n, signed) {
|
|
while (dataBufferLength < n) {
|
|
dataBuffer = dataBuffer << 8 | data[dataPosition++];
|
|
dataBufferLength += 8;
|
|
}
|
|
dataBufferLength -= n;
|
|
return dataBuffer >>> dataBufferLength & (1 << n) - 1;
|
|
}
|
|
var dataPosition = 0;
|
|
var dataBuffer = 0;
|
|
var dataBufferLength = 0;
|
|
var pcmPosition = 0;
|
|
var codeSize = readBits(2);
|
|
var indexTable = ACPCMIndexTables[codeSize];
|
|
while (pcmPosition < pcm16.length) {
|
|
var x = pcm16[pcmPosition++] = readBits(16) << 16 >> 16, x2;
|
|
var stepIndex = readBits(6), stepIndex2;
|
|
if (channels > 1) {
|
|
x2 = pcm16[pcmPosition++] = readBits(16) << 16 >> 16;
|
|
stepIndex2 = readBits(6);
|
|
}
|
|
var signMask = 1 << codeSize + 1;
|
|
for (var i = 0; i < 4095; i++) {
|
|
var nibble = readBits(codeSize + 2);
|
|
var step = ACPCMStepSizeTable[stepIndex];
|
|
var sum = 0;
|
|
for (var currentBit = signMask >> 1; currentBit; currentBit >>= 1, step >>= 1) {
|
|
if (nibble & currentBit)
|
|
sum += step;
|
|
}
|
|
x += (nibble & signMask ? -1 : 1) * (sum + step);
|
|
pcm16[pcmPosition++] = x = x < -32768 ? -32768 : x > 32767 ? 32767 : x;
|
|
stepIndex += indexTable[nibble & ~signMask];
|
|
stepIndex = stepIndex < 0 ? 0 : stepIndex > 88 ? 88 : stepIndex;
|
|
if (channels > 1) {
|
|
nibble = readBits(codeSize + 2);
|
|
step = ACPCMStepSizeTable[stepIndex2];
|
|
sum = 0;
|
|
for (var currentBit = signMask >> 1; currentBit; currentBit >>= 1, step >>= 1) {
|
|
if (nibble & currentBit)
|
|
sum += step;
|
|
}
|
|
x2 += (nibble & signMask ? -1 : 1) * (sum + step);
|
|
pcm16[pcmPosition++] = x2 = x2 < -32768 ? -32768 : x2 > 32767 ? 32767 : x2;
|
|
stepIndex2 += indexTable[nibble & ~signMask];
|
|
stepIndex2 = stepIndex2 < 0 ? 0 : stepIndex2 > 88 ? 88 : stepIndex2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var nextSoundStreamId = 0;
|
|
function SwfSoundStream(samplesCount, sampleRate, channels) {
|
|
this.streamId = nextSoundStreamId++;
|
|
this.samplesCount = samplesCount;
|
|
this.sampleRate = sampleRate;
|
|
this.channels = channels;
|
|
this.format = null;
|
|
this.currentSample = 0;
|
|
}
|
|
SwfSoundStream.prototype = {
|
|
get info() {
|
|
return {
|
|
samplesCount: this.samplesCount,
|
|
sampleRate: this.sampleRate,
|
|
channels: this.channels,
|
|
format: this.format,
|
|
streamId: this.streamId
|
|
};
|
|
},
|
|
decode: function (data) {
|
|
throw new Error('SwfSoundStream.decode: not implemented');
|
|
}
|
|
};
|
|
function SwfSoundStream_decode_PCM(data) {
|
|
var pcm = new Float32Array(data.length);
|
|
for (var i = 0; i < pcm.length; i++)
|
|
pcm[i] = (data[i] - 128) / 128;
|
|
this.currentSample += pcm.length / this.channels;
|
|
return {
|
|
streamId: this.streamId,
|
|
samplesCount: pcm.length / this.channels,
|
|
pcm: pcm
|
|
};
|
|
}
|
|
function SwfSoundStream_decode_PCM_be(data) {
|
|
var pcm = new Float32Array(data.length / 2);
|
|
for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
|
|
pcm[i] = (data[j] << 24 | data[j + 1] << 16) / 2147483648;
|
|
this.currentSample += pcm.length / this.channels;
|
|
return {
|
|
streamId: this.streamId,
|
|
samplesCount: pcm.length / this.channels,
|
|
pcm: pcm
|
|
};
|
|
}
|
|
function SwfSoundStream_decode_PCM_le(data) {
|
|
var pcm = new Float32Array(data.length / 2);
|
|
for (var i = 0, j = 0; i < pcm.length; i++, j += 2)
|
|
pcm[i] = (data[j + 1] << 24 | data[j] << 16) / 2147483648;
|
|
this.currentSample += pcm.length / this.channels;
|
|
return {
|
|
streamId: this.streamId,
|
|
samplesCount: pcm.length / this.channels,
|
|
pcm: pcm
|
|
};
|
|
}
|
|
function SwfSoundStream_decode_MP3(data) {
|
|
var samplesCount = data[1] << 8 | data[0];
|
|
var seek = data[3] << 8 | data[2];
|
|
this.currentSample += samplesCount;
|
|
return {
|
|
streamId: this.streamId,
|
|
samplesCount: samplesCount,
|
|
data: new Uint8Array(data.subarray(4)),
|
|
seek: seek
|
|
};
|
|
}
|
|
function createSoundStream(tag) {
|
|
var channels = tag.streamType == SOUND_TYPE_STEREO ? 2 : 1;
|
|
var samplesCount = tag.samplesCount;
|
|
var sampleRate = SOUND_RATES[tag.streamRate];
|
|
var stream = new SwfSoundStream(samplesCount, sampleRate, channels);
|
|
switch (tag.streamCompression) {
|
|
case SOUND_FORMAT_PCM_BE:
|
|
stream.format = 'wave';
|
|
if (tag.soundSize == SOUND_SIZE_16_BIT) {
|
|
stream.decode = SwfSoundStream_decode_PCM_be;
|
|
} else {
|
|
stream.decode = SwfSoundStream_decode_PCM;
|
|
}
|
|
break;
|
|
case SOUND_FORMAT_PCM_LE:
|
|
stream.format = 'wave';
|
|
if (tag.soundSize == SOUND_SIZE_16_BIT) {
|
|
stream.decode = SwfSoundStream_decode_PCM_le;
|
|
} else {
|
|
stream.decode = SwfSoundStream_decode_PCM;
|
|
}
|
|
break;
|
|
case SOUND_FORMAT_MP3:
|
|
stream.format = 'mp3';
|
|
stream.decode = SwfSoundStream_decode_MP3;
|
|
break;
|
|
default:
|
|
throw new Error('Unsupported audio format: ' + tag.soundFormat);
|
|
}
|
|
return stream;
|
|
}
|
|
function defineText(tag, dictionary) {
|
|
var dependencies = [];
|
|
if (tag.hasFont) {
|
|
var font = dictionary[tag.fontId];
|
|
tag.font = font.uniqueName;
|
|
dependencies.push(font.id);
|
|
}
|
|
var props = {
|
|
type: 'text',
|
|
id: tag.id,
|
|
variableName: tag.variableName,
|
|
tag: tag
|
|
};
|
|
if (dependencies.length)
|
|
props.require = dependencies;
|
|
return props;
|
|
}
|
|
var isWorker = typeof window === 'undefined';
|
|
if (isWorker) {
|
|
importScripts('../../../lib/mp3/mp3.js');
|
|
self.addEventListener('message', function (e) {
|
|
var data = e.data;
|
|
var sessionId = data.sessionId;
|
|
try {
|
|
switch (data.action) {
|
|
case 'create':
|
|
var session = new Session(sessionId);
|
|
sessions[sessionId] = session;
|
|
break;
|
|
case 'close':
|
|
var session = sessions[sessionId];
|
|
if (session) {
|
|
session.close();
|
|
sessions[sessionId] = null;
|
|
}
|
|
break;
|
|
case 'decode':
|
|
var session = sessions[sessionId];
|
|
if (!session) {
|
|
throw new Error('mp3 decoding session is unavailable');
|
|
}
|
|
session.decode(data.data);
|
|
break;
|
|
}
|
|
} catch (ex) {
|
|
self.postMessage({
|
|
sessionId: sessionId,
|
|
action: 'error',
|
|
message: ex.message
|
|
});
|
|
}
|
|
}, false);
|
|
var sessions = {};
|
|
function Session(id) {
|
|
this.id = id;
|
|
if (typeof MP3Decoder === 'undefined') {
|
|
throw new Error('mp3 decoder is not available');
|
|
}
|
|
var decoder = new MP3Decoder();
|
|
decoder.onframedata = function (frameData, channels, sampleRate, bitRate) {
|
|
self.postMessage({
|
|
sessionId: this.id,
|
|
action: 'frame',
|
|
frameData: frameData,
|
|
channels: channels,
|
|
sampleRate: sampleRate,
|
|
bitRate: bitRate
|
|
});
|
|
}.bind(this);
|
|
decoder.onid3tag = function (data) {
|
|
self.postMessage({
|
|
sessionId: this.id,
|
|
action: 'id3',
|
|
id3Data: data
|
|
});
|
|
}.bind(this);
|
|
this.decoder = decoder;
|
|
}
|
|
Session.prototype = {
|
|
decode: function (data) {
|
|
this.decoder.push(data);
|
|
},
|
|
close: function () {
|
|
self.postMessage({
|
|
sessionId: this.id,
|
|
action: 'closed'
|
|
});
|
|
}
|
|
};
|
|
self.console = {
|
|
log: function (s) {
|
|
self.postMessage({
|
|
action: 'console',
|
|
method: 'log',
|
|
message: s
|
|
});
|
|
},
|
|
error: function (s) {
|
|
self.postMessage({
|
|
action: 'console',
|
|
method: 'error',
|
|
message: s
|
|
});
|
|
}
|
|
};
|
|
} else {
|
|
var mp3Worker;
|
|
function createMP3Worker() {
|
|
var worker = new Worker(SHUMWAY_ROOT + 'swf/mp3worker.js');
|
|
worker.addEventListener('message', function (e) {
|
|
if (e.data.action === 'console') {
|
|
console[e.data.method].call(console, e.data.message);
|
|
}
|
|
});
|
|
return worker;
|
|
}
|
|
var nextSessionId = 0;
|
|
function MP3DecoderSession() {
|
|
mp3Worker = mp3Worker || createMP3Worker();
|
|
var sessionId = nextSessionId++;
|
|
this.id = sessionId;
|
|
this.onworkermessage = function (e) {
|
|
if (e.data.sessionId !== sessionId)
|
|
return;
|
|
var action = e.data.action;
|
|
switch (action) {
|
|
case 'closed':
|
|
if (this.onclosed)
|
|
this.onclosed();
|
|
mp3Worker.removeEventListener('message', this.onworkermessage, false);
|
|
break;
|
|
case 'frame':
|
|
this.onframedata(e.data.frameData, e.data.channels, e.data.sampleRate, e.data.bitRate);
|
|
break;
|
|
case 'id3':
|
|
if (this.onid3tag)
|
|
this.onid3tag(e.data.id3Data);
|
|
break;
|
|
case 'error':
|
|
if (this.onerror)
|
|
this.onerror(e.data.message);
|
|
break;
|
|
}
|
|
}.bind(this);
|
|
mp3Worker.addEventListener('message', this.onworkermessage, false);
|
|
mp3Worker.postMessage({
|
|
sessionId: sessionId,
|
|
action: 'create'
|
|
});
|
|
}
|
|
MP3DecoderSession.prototype = {
|
|
pushAsync: function (data) {
|
|
mp3Worker.postMessage({
|
|
sessionId: this.id,
|
|
action: 'decode',
|
|
data: data
|
|
});
|
|
},
|
|
close: function () {
|
|
mp3Worker.postMessage({
|
|
sessionId: this.id,
|
|
action: 'close'
|
|
});
|
|
}
|
|
};
|
|
MP3DecoderSession.processAll = function (data, onloaded) {
|
|
var currentBufferSize = 8000;
|
|
var currentBuffer = new Float32Array(currentBufferSize);
|
|
var bufferPosition = 0;
|
|
var id3Tags = [];
|
|
var sessionAborted = false;
|
|
var session = new MP3DecoderSession();
|
|
session.onframedata = function (frameData, channels, sampleRate, bitRate) {
|
|
var needed = frameData.length + bufferPosition;
|
|
if (needed > currentBufferSize) {
|
|
do {
|
|
currentBufferSize *= 2;
|
|
} while (needed > currentBufferSize);
|
|
var newBuffer = new Float32Array(currentBufferSize);
|
|
newBuffer.set(currentBuffer);
|
|
currentBuffer = newBuffer;
|
|
}
|
|
currentBuffer.set(frameData, bufferPosition);
|
|
bufferPosition += frameData.length;
|
|
};
|
|
session.onid3tag = function (tagData) {
|
|
id3Tags.push(tagData);
|
|
};
|
|
session.onclosed = function () {
|
|
if (sessionAborted)
|
|
return;
|
|
onloaded(currentBuffer.subarray(0, bufferPosition), id3Tags);
|
|
};
|
|
session.onerror = function (error) {
|
|
if (sessionAborted)
|
|
return;
|
|
sessionAborted = true;
|
|
onloaded(null, null, error);
|
|
};
|
|
session.pushAsync(data);
|
|
session.close();
|
|
};
|
|
}
|
|
SWF.embed = function (file, doc, container, options) {
|
|
var canvas = doc.createElement('canvas');
|
|
var ctx = canvas.getContext('2d');
|
|
var loader = new flash.display.Loader();
|
|
var loaderInfo = loader._contentLoaderInfo;
|
|
var stage = new flash.display.Stage();
|
|
var pixelRatio = 1;
|
|
var forceHidpiSetting = forceHidpi.value;
|
|
stage._loader = loader;
|
|
loaderInfo._parameters = options.movieParams;
|
|
loaderInfo._url = options.url || (typeof file === 'string' ? file : null);
|
|
loaderInfo._loaderURL = options.loaderURL || loaderInfo._url;
|
|
loader._parent = stage;
|
|
loader._stage = stage;
|
|
function setCanvasSize(width, height) {
|
|
if (pixelRatio === 1) {
|
|
canvas.width = width | 0;
|
|
canvas.height = height | 0;
|
|
return;
|
|
}
|
|
var canvasWidth = Math.floor(width * pixelRatio);
|
|
var canvasHeight = Math.floor(height * pixelRatio);
|
|
canvas.style.width = canvasWidth / pixelRatio + 'px';
|
|
canvas.style.height = canvasHeight / pixelRatio + 'px';
|
|
canvas.width = canvasWidth;
|
|
canvas.height = canvasHeight;
|
|
}
|
|
function fitCanvas(container) {
|
|
setCanvasSize(container.clientWidth, container.clientHeight);
|
|
stage._invalid = true;
|
|
}
|
|
loaderInfo._addEventListener('init', function () {
|
|
if (forceHidpiSetting || loaderInfo._swfVersion >= 18) {
|
|
pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1;
|
|
}
|
|
canvas._pixelRatio = pixelRatio;
|
|
stage._contentsScaleFactor = pixelRatio;
|
|
if (container.clientHeight) {
|
|
fitCanvas(container);
|
|
window.addEventListener('resize', function () {
|
|
fitCanvas(container);
|
|
});
|
|
} else {
|
|
setCanvasSize(stage._stageWidth / 20, stage._stageHeight / 20);
|
|
}
|
|
container.setAttribute('style', 'position: relative');
|
|
canvas.addEventListener('click', function () {
|
|
ShumwayKeyboardListener.focus = stage;
|
|
stage._mouseTarget._dispatchEvent('click');
|
|
});
|
|
canvas.addEventListener('dblclick', function () {
|
|
if (stage._mouseTarget._doubleClickEnabled) {
|
|
stage._mouseTarget._dispatchEvent('doubleClick');
|
|
}
|
|
});
|
|
canvas.addEventListener('mousedown', function () {
|
|
stage._mouseEvents.push('mousedown');
|
|
});
|
|
canvas.addEventListener('mousemove', function (domEvt) {
|
|
var node = this;
|
|
var left = 0;
|
|
var top = 0;
|
|
if (node.offsetParent) {
|
|
do {
|
|
left += node.offsetLeft;
|
|
top += node.offsetTop;
|
|
} while (node = node.offsetParent);
|
|
}
|
|
var m = stage._concatenatedTransform;
|
|
var mouseX = ((domEvt.pageX - left) * pixelRatio - m.tx / 20) / m.a;
|
|
var mouseY = ((domEvt.pageY - top) * pixelRatio - m.ty / 20) / m.d;
|
|
if (mouseX !== stage._mouseX || mouseY !== stage._mouseY) {
|
|
stage._mouseMoved = true;
|
|
stage._mouseX = mouseX * 20;
|
|
stage._mouseY = mouseY * 20;
|
|
}
|
|
});
|
|
canvas.addEventListener('mouseup', function () {
|
|
stage._mouseEvents.push('mouseup');
|
|
});
|
|
canvas.addEventListener('mouseover', function () {
|
|
stage._mouseMoved = true;
|
|
stage._mouseOver = true;
|
|
});
|
|
canvas.addEventListener('mouseout', function () {
|
|
stage._mouseMoved = true;
|
|
stage._mouseOver = false;
|
|
});
|
|
window.addEventListener('message', function (evt) {
|
|
var data = evt.data;
|
|
if (typeof data !== 'object' || data === null) {
|
|
return;
|
|
}
|
|
var type = data.type;
|
|
switch (type) {
|
|
case 'mousemove':
|
|
case 'mouseup':
|
|
case 'mousedown':
|
|
var isMouseMove = type === 'mousemove';
|
|
stage._mouseMoved = true;
|
|
stage._mouseOver = true;
|
|
stage._mouseX = data.x * 20;
|
|
stage._mouseY = data.y * 20;
|
|
if (!isMouseMove) {
|
|
stage._mouseEvents.push(type);
|
|
}
|
|
break;
|
|
case 'mouseover':
|
|
case 'mouseout':
|
|
stage._mouseMoved = true;
|
|
stage._mouseOver = type === 'mouseover';
|
|
break;
|
|
case 'keyup':
|
|
case 'keydown':
|
|
stage._dispatchEvent(new flash.events.KeyboardEvent(type === 'keyup' ? 'keyUp' : 'keyDown', true, false, data.charCode, data.keyCode, data.keyLocation, data.ctrlKey || false, data.altKey || false, data.shiftKey || false));
|
|
break;
|
|
}
|
|
}, false);
|
|
var bgcolor = loaderInfo._backgroundColor;
|
|
if (options.objectParams) {
|
|
var m;
|
|
if (options.objectParams.bgcolor && (m = /#([0-9A-F]{6})/i.exec(options.objectParams.bgcolor))) {
|
|
var hexColor = parseInt(m[1], 16);
|
|
bgcolor = {
|
|
red: hexColor >> 16 & 255,
|
|
green: hexColor >> 8 & 255,
|
|
blue: hexColor & 255,
|
|
alpha: 255
|
|
};
|
|
}
|
|
if (options.objectParams.wmode === 'transparent') {
|
|
bgcolor = {
|
|
red: 0,
|
|
green: 0,
|
|
blue: 0,
|
|
alpha: 0
|
|
};
|
|
}
|
|
}
|
|
stage._color = bgcolor;
|
|
ctx.fillStyle = rgbaObjToStr(bgcolor);
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
var root = loader._content;
|
|
root._dispatchEvent('added', undefined, true);
|
|
root._dispatchEvent('addedToStage');
|
|
container.appendChild(canvas);
|
|
stage._domContainer = container;
|
|
if (options.onStageInitialized) {
|
|
options.onStageInitialized(stage);
|
|
}
|
|
var startPromise = options.startPromise || Promise.resolve();
|
|
startPromise.then(function () {
|
|
renderStage(stage, ctx, options);
|
|
});
|
|
});
|
|
if (options.onParsed) {
|
|
loaderInfo._addEventListener('parsed', function () {
|
|
options.onParsed();
|
|
});
|
|
}
|
|
if (options.onComplete) {
|
|
loaderInfo._addEventListener('complete', function () {
|
|
options.onComplete();
|
|
});
|
|
}
|
|
loader._load(typeof file === 'string' ? new flash.net.URLRequest(file) : file);
|
|
return loader;
|
|
};
|
|
var rendererOptions = coreOptions.register(new OptionSet('Renderer Options'));
|
|
var traceRenderer = rendererOptions.register(new Option('tr', 'traceRenderer', 'number', 0, 'trace renderer execution'));
|
|
var disableRenderVisitor = rendererOptions.register(new Option('drv', 'disableRenderVisitor', 'boolean', false, 'disable render visitor'));
|
|
var disableMouseVisitor = rendererOptions.register(new Option('dmv', 'disableMouseVisitor', 'boolean', false, 'disable mouse visitor'));
|
|
var showRedrawRegions = rendererOptions.register(new Option('rr', 'showRedrawRegions', 'boolean', false, 'show redraw regions'));
|
|
var renderAsWireframe = rendererOptions.register(new Option('raw', 'renderAsWireframe', 'boolean', false, 'render as wireframe'));
|
|
var showQuadTree = rendererOptions.register(new Option('qt', 'showQuadTree', 'boolean', false, 'show quad tree'));
|
|
var turboMode = rendererOptions.register(new Option('', 'turbo', 'boolean', false, 'turbo mode'));
|
|
var forceHidpi = rendererOptions.register(new Option('', 'forceHidpi', 'boolean', false, 'force hidpi'));
|
|
var skipFrameDraw = rendererOptions.register(new Option('', 'skipFrameDraw', 'boolean', false, 'skip frame when not on time'));
|
|
var hud = rendererOptions.register(new Option('', 'hud', 'boolean', false, 'show hud mode'));
|
|
var dummyAnimation = rendererOptions.register(new Option('', 'dummy', 'boolean', false, 'show test balls animation'));
|
|
var enableConstructChildren = rendererOptions.register(new Option('', 'constructChildren', 'boolean', true, 'Construct Children'));
|
|
var enableEnterFrame = rendererOptions.register(new Option('', 'enterFrame', 'boolean', true, 'Enter Frame'));
|
|
var enableAdvanceFrame = rendererOptions.register(new Option('', 'advanceFrame', 'boolean', true, 'Advance Frame'));
|
|
var CanvasCache = {
|
|
cache: [],
|
|
getCanvas: function getCanvas(protoCanvas) {
|
|
var tempCanvas = this.cache.shift();
|
|
if (!tempCanvas) {
|
|
tempCanvas = {
|
|
canvas: document.createElement('canvas')
|
|
};
|
|
tempCanvas.ctx = tempCanvas.canvas.getContext('2d');
|
|
}
|
|
tempCanvas.canvas.width = protoCanvas.width;
|
|
tempCanvas.canvas.height = protoCanvas.height;
|
|
tempCanvas.ctx.save();
|
|
return tempCanvas;
|
|
},
|
|
releaseCanvas: function releaseCanvas(tempCanvas) {
|
|
tempCanvas.ctx.restore();
|
|
this.cache.push(tempCanvas);
|
|
}
|
|
};
|
|
function isCanvasVisible(canvas) {
|
|
if (canvas.ownerDocument.hidden) {
|
|
return false;
|
|
}
|
|
if (canvas.mozVisible === false) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function visitContainer(container, visitor, context) {
|
|
var children = container._children;
|
|
visitor.childrenStart(container);
|
|
for (var i = 0, n = children.length; i < n; i++) {
|
|
var child = children[i];
|
|
if (!child) {
|
|
continue;
|
|
}
|
|
if (visitor.ignoreVisibleAttribute || child._visible && !child._maskedObject) {
|
|
visitor.visit(child, visitContainer, context);
|
|
}
|
|
}
|
|
visitor.childrenEnd(container);
|
|
}
|
|
var BlendModeNameMap = {
|
|
'normal': 'normal',
|
|
'multiply': 'multiply',
|
|
'screen': 'screen',
|
|
'lighten': 'lighten',
|
|
'darken': 'darken',
|
|
'difference': 'difference',
|
|
'overlay': 'overlay',
|
|
'hardlight': 'hard-light'
|
|
};
|
|
function getBlendModeName(blendMode) {
|
|
return BlendModeNameMap[blendMode] || 'normal';
|
|
}
|
|
function RenderVisitor(root, ctx, invalidPath, refreshStage) {
|
|
this.root = root;
|
|
this.ctx = ctx;
|
|
this.depth = 0;
|
|
this.invalidPath = invalidPath;
|
|
this.refreshStage = refreshStage;
|
|
this.clipDepth = null;
|
|
this.clipStack = null;
|
|
}
|
|
RenderVisitor.prototype = {
|
|
ignoreVisibleAttribute: false,
|
|
start: function () {
|
|
visitContainer(this.root, this, new RenderingContext(this.refreshStage, this.invalidPath));
|
|
},
|
|
startFragment: function (matrix) {
|
|
var root = this.root;
|
|
var currentTransform = root._currentTransform;
|
|
var t = currentTransform;
|
|
if (matrix) {
|
|
t = root._currentTransform = {
|
|
a: matrix.a,
|
|
b: matrix.b,
|
|
c: matrix.c,
|
|
d: matrix.d,
|
|
tx: matrix.tx * 20 | 0,
|
|
ty: matrix.ty * 20 | 0
|
|
};
|
|
root._invalidateTransform();
|
|
}
|
|
var inverse;
|
|
if (t) {
|
|
inverse = new flash.geom.Matrix(t.a, t.b, t.c, t.d, t.tx / 20, t.ty / 20);
|
|
inverse.invert();
|
|
this.ctx.save();
|
|
this.ctx.transform(inverse.a, inverse.b, inverse.c, inverse.d, inverse.tx, inverse.ty);
|
|
}
|
|
this.visit(root, visitContainer, new RenderingContext(this.refreshStage, this.invalidPath));
|
|
if (t) {
|
|
this.ctx.restore();
|
|
}
|
|
if (matrix) {
|
|
root._currentTransform = currentTransform;
|
|
root._invalidateTransform();
|
|
}
|
|
},
|
|
childrenStart: function (parent) {
|
|
if (this.depth === 0) {
|
|
var ctx = this.ctx;
|
|
ctx.save();
|
|
if (this.invalidPath && !this.refreshStage && !renderAsWireframe.value) {
|
|
this.invalidPath.draw(ctx, false, 0, null);
|
|
ctx.clip();
|
|
}
|
|
var bgcolor = this.root._color;
|
|
if (bgcolor) {
|
|
if (bgcolor.alpha < 255) {
|
|
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
}
|
|
if (bgcolor.alpha > 0) {
|
|
ctx.fillStyle = rgbaObjToStr(bgcolor);
|
|
if (this.invalidPath && !this.refreshStage && !renderAsWireframe.value) {
|
|
ctx.fill();
|
|
} else {
|
|
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
}
|
|
}
|
|
}
|
|
ctx.mozFillRule = 'evenodd';
|
|
}
|
|
this.depth++;
|
|
if (this.clipDepth && this.clipDepth.length > 0) {
|
|
this.clipStack = {
|
|
depth: this.depth,
|
|
clip: this.clipDepth,
|
|
next: this.clipStack
|
|
};
|
|
this.clipDepth = null;
|
|
}
|
|
},
|
|
childrenEnd: function (parent) {
|
|
if (this.clipDepth) {
|
|
while (this.clipDepth.length > 0) {
|
|
var clipDepthInfo = this.clipDepth.pop();
|
|
this.clipEnd(clipDepthInfo);
|
|
this.ctx = clipDepthInfo.ctx;
|
|
}
|
|
this.clipDepth = null;
|
|
}
|
|
if (this.clipStack && this.clipStack.depth === this.depth) {
|
|
this.clipDepth = this.clipStack.clip;
|
|
this.clipStack = this.clipStack.next;
|
|
}
|
|
this.depth--;
|
|
if (this.depth === 0) {
|
|
this.ctx.restore();
|
|
this.invalidPath = null;
|
|
}
|
|
},
|
|
visit: function (child, visitContainer, context) {
|
|
var ctx = this.ctx;
|
|
var parentHasClippingMask = context.isClippingMask;
|
|
var parentColorTransform = context.colorTransform;
|
|
var clippingMask = parentHasClippingMask === true;
|
|
if (child._cxform) {
|
|
context.colorTransform = parentColorTransform.applyCXForm(child._cxform);
|
|
}
|
|
if (!clippingMask) {
|
|
while (this.clipDepth && this.clipDepth.length > 0 && child._depth > this.clipDepth[0].clipDepth) {
|
|
var clipDepthInfo = this.clipDepth.shift();
|
|
this.clipEnd(clipDepthInfo);
|
|
context.parentCtxs.shift();
|
|
ctx = this.ctx = clipDepthInfo.ctx;
|
|
}
|
|
if (this.clipDepth && this.clipDepth.length > 0 && child._depth <= this.clipDepth[0].clipDepth) {
|
|
ctx = this.ctx = this.clipDepth[0].maskee.ctx;
|
|
}
|
|
if (child._clipDepth) {
|
|
context.isClippingMask = clippingMask = true;
|
|
var clipDepthInfo = this.clipStart(child);
|
|
if (!this.clipDepth) {
|
|
this.clipDepth = [
|
|
clipDepthInfo
|
|
];
|
|
} else {
|
|
this.clipDepth.unshift(clipDepthInfo);
|
|
}
|
|
context.parentCtxs.unshift(ctx);
|
|
ctx = this.ctx = clipDepthInfo.mask.ctx;
|
|
}
|
|
}
|
|
if (clippingMask && child._isContainer) {
|
|
ctx.save();
|
|
renderDisplayObject(child, ctx, context);
|
|
for (var i = 0, n = child._children.length; i < n; i++) {
|
|
var child1 = child._children[i];
|
|
if (!child1) {
|
|
continue;
|
|
}
|
|
if (this.ignoreVisibleAttribute || child1._visible && !child1._maskedObject) {
|
|
this.visit(child1, visitContainer, context);
|
|
}
|
|
}
|
|
ctx.restore();
|
|
ctx.fill();
|
|
context.isClippingMask = parentHasClippingMask;
|
|
context.colorTransform = parentColorTransform;
|
|
return;
|
|
}
|
|
ctx.save();
|
|
ctx.globalCompositeOperation = getBlendModeName(child._blendMode);
|
|
if (child._mask) {
|
|
var clipInfo = this.clipStart(child);
|
|
var mask = clipInfo.mask;
|
|
var maskee = clipInfo.maskee;
|
|
context.parentCtxs.push(ctx);
|
|
var savedClipDepth = this.clipDepth;
|
|
this.clipDepth = null;
|
|
this.ctx = mask.ctx;
|
|
this.visit(child._mask, visitContainer, new RenderingContext(this.refreshStage));
|
|
this.ctx = ctx;
|
|
this.clipDepth = savedClipDepth;
|
|
renderDisplayObject(child, maskee.ctx, context);
|
|
if (child._isContainer) {
|
|
this.ctx = maskee.ctx;
|
|
visitContainer(child, this, context);
|
|
this.ctx = ctx;
|
|
}
|
|
context.parentCtxs.pop();
|
|
this.clipEnd(clipInfo);
|
|
} else {
|
|
renderDisplayObject(child, ctx, context);
|
|
if (child._isContainer) {
|
|
visitContainer(child, this, context);
|
|
}
|
|
}
|
|
ctx.restore();
|
|
if (clippingMask) {
|
|
ctx.fill();
|
|
}
|
|
context.isClippingMask = parentHasClippingMask;
|
|
context.colorTransform = parentColorTransform;
|
|
},
|
|
clipStart: function (child) {
|
|
var m = child._parent._getConcatenatedTransform(null, true);
|
|
var tx = m.tx / 20;
|
|
var ty = m.ty / 20;
|
|
var mask = CanvasCache.getCanvas(this.ctx.canvas);
|
|
mask.ctx.setTransform(m.a, m.b, m.c, m.d, tx, ty);
|
|
var maskee = CanvasCache.getCanvas(this.ctx.canvas);
|
|
maskee.ctx.setTransform(m.a, m.b, m.c, m.d, tx, ty);
|
|
var clipInfo = {
|
|
ctx: this.ctx,
|
|
mask: mask,
|
|
maskee: maskee,
|
|
clipDepth: child._clipDepth
|
|
};
|
|
return clipInfo;
|
|
},
|
|
clipEnd: function (clipInfo) {
|
|
var ctx = clipInfo.ctx;
|
|
var mask = clipInfo.mask;
|
|
var maskee = clipInfo.maskee;
|
|
maskee.ctx.globalCompositeOperation = 'destination-in';
|
|
maskee.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
maskee.ctx.drawImage(mask.canvas, 0, 0);
|
|
ctx.save();
|
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
ctx.drawImage(maskee.canvas, 0, 0);
|
|
ctx.restore();
|
|
CanvasCache.releaseCanvas(mask);
|
|
CanvasCache.releaseCanvas(maskee);
|
|
}
|
|
};
|
|
function RenderingColorTransform() {
|
|
this.mode = null;
|
|
this.transform = [
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0
|
|
];
|
|
}
|
|
RenderingColorTransform.prototype = {
|
|
applyCXForm: function (cxform) {
|
|
var t = this.transform;
|
|
t = [
|
|
t[0] * cxform.redMultiplier / 256,
|
|
t[1] * cxform.greenMultiplier / 256,
|
|
t[2] * cxform.blueMultiplier / 256,
|
|
t[3] * cxform.alphaMultiplier / 256,
|
|
t[4] * cxform.redMultiplier / 256 + cxform.redOffset,
|
|
t[5] * cxform.greenMultiplier / 256 + cxform.greenOffset,
|
|
t[6] * cxform.blueMultiplier / 256 + cxform.blueOffset,
|
|
t[7] * cxform.alphaMultiplier / 256 + cxform.alphaOffset
|
|
];
|
|
var mode;
|
|
var PRECISION = 0.0001;
|
|
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) {
|
|
mode = Math.abs(t[3] - 1) < PRECISION ? null : 'simple';
|
|
} else {
|
|
mode = 'complex';
|
|
}
|
|
var clone = Object.create(RenderingColorTransform.prototype);
|
|
clone.mode = mode;
|
|
clone.transform = t;
|
|
return clone;
|
|
},
|
|
setFillStyle: function (ctx, style) {
|
|
if (this.mode === 'complex') {
|
|
style = typeof style === 'function' ? style(ctx, this) : this.convertColor(style);
|
|
} else if (typeof style === 'number') {
|
|
style = this.convertNumericColor(style);
|
|
} else if (typeof style === 'function') {
|
|
style = style.defaultFillStyle;
|
|
}
|
|
ctx.fillStyle = style;
|
|
},
|
|
setStrokeStyle: function (ctx, style) {
|
|
if (this.mode === 'complex') {
|
|
style = typeof style === 'function' ? style(ctx, this) : this.convertColor(style);
|
|
} else if (typeof style === 'number') {
|
|
style = this.convertNumericColor(style);
|
|
} else if (typeof style === 'function') {
|
|
style = style.defaultFillStyle;
|
|
}
|
|
ctx.strokeStyle = style;
|
|
},
|
|
addGradientColorStop: function (gradient, ratio, style) {
|
|
if (this.mode === 'complex') {
|
|
style = this.convertColor(style);
|
|
} else if (typeof style === 'number') {
|
|
style = this.convertNumericColor(style);
|
|
}
|
|
gradient.addColorStop(ratio, style);
|
|
},
|
|
setAlpha: function (ctx, force) {
|
|
if (this.mode === 'simple' || force) {
|
|
var t = this.transform;
|
|
ctx.globalAlpha = Math.min(1, Math.max(0, ctx.globalAlpha * t[3]));
|
|
}
|
|
},
|
|
convertNumericColor: function (num) {
|
|
return '#' + (num | 16777216).toString(16).substr(1);
|
|
},
|
|
convertColor: function (style) {
|
|
var t = this.transform;
|
|
var m;
|
|
switch (typeof style) {
|
|
case 'string':
|
|
if (style[0] === '#') {
|
|
m = [
|
|
undefined,
|
|
parseInt(style.substr(1, 2), 16),
|
|
parseInt(style.substr(3, 2), 16),
|
|
parseInt(style.substr(5, 2), 16),
|
|
1
|
|
];
|
|
}
|
|
m = m || /rgba\(([^,]+),([^,]+),([^,]+),([^)]+)\)/.exec(style);
|
|
if (!m) {
|
|
return style;
|
|
}
|
|
break;
|
|
case 'number':
|
|
m = [
|
|
style,
|
|
style >> 16 & 255,
|
|
style >> 8 & 255,
|
|
style & 255,
|
|
1
|
|
];
|
|
break;
|
|
default:
|
|
return style;
|
|
}
|
|
var r = Math.min(255, Math.max(0, m[1] * t[0] + t[4])) | 0;
|
|
var g = Math.min(255, Math.max(0, m[2] * t[1] + t[5])) | 0;
|
|
var b = Math.min(255, Math.max(0, m[3] * t[2] + t[6])) | 0;
|
|
var a = Math.min(1, Math.max(0, m[4] * t[3] + t[7] / 256));
|
|
return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
|
|
},
|
|
getTransformFingerprint: function () {
|
|
return this.transform.join('|');
|
|
}
|
|
};
|
|
function RenderingContext(refreshStage, invalidPath) {
|
|
this.refreshStage = refreshStage === true;
|
|
this.invalidPath = invalidPath;
|
|
this.isClippingMask = false;
|
|
this.colorTransform = new RenderingColorTransform();
|
|
this.parentCtxs = [];
|
|
}
|
|
function renderDisplayObject(child, ctx, context) {
|
|
var m = child._currentTransform;
|
|
if (m) {
|
|
ctx.transform(m.a, m.b, m.c, m.d, m.tx / 20, m.ty / 20);
|
|
}
|
|
if (!renderAsWireframe.value) {
|
|
if (child._alpha !== 1) {
|
|
ctx.globalAlpha *= child._alpha;
|
|
}
|
|
if (context.invalidPath && !child._invalid && !context.refreshStage) {
|
|
return;
|
|
}
|
|
if (child._graphics) {
|
|
var graphics = child._graphics;
|
|
if (graphics._bitmap) {
|
|
ctx.save();
|
|
ctx.translate(child._bbox.xMin / 20, child._bbox.yMin / 20);
|
|
context.colorTransform.setAlpha(ctx, true);
|
|
ctx.drawImage(graphics._bitmap, 0, 0);
|
|
ctx.restore();
|
|
} else {
|
|
var ratio = child.ratio;
|
|
if (ratio === undefined) {
|
|
ratio = 0;
|
|
}
|
|
graphics.draw(ctx, context.isClippingMask, ratio, context.colorTransform);
|
|
}
|
|
}
|
|
if (child.draw) {
|
|
child.draw(ctx, child.ratio, context.colorTransform, context.parentCtxs);
|
|
}
|
|
} else {
|
|
if (!child._invalid && !context.refreshStage) {
|
|
return;
|
|
}
|
|
if (child.getBounds) {
|
|
var b = child.getBounds(null);
|
|
if (b && b.xMax - b.xMin > 0 && b.yMax - b.yMin > 0) {
|
|
if (!child._wireframeStrokeStyle) {
|
|
child._wireframeStrokeStyle = randomStyle();
|
|
}
|
|
ctx.save();
|
|
ctx.strokeStyle = child._wireframeStrokeStyle;
|
|
var x = b.xMin / 20;
|
|
var y = b.yMin / 20;
|
|
ctx.strokeRect(x + 0.5, y + 0.5, b.xMax / 20 - x - 1, b.yMax / 20 - y - 1);
|
|
ctx.restore();
|
|
}
|
|
}
|
|
}
|
|
child._invalid = false;
|
|
}
|
|
function renderQuadTree(ctx, qtree) {
|
|
ctx.strokeRect(qtree.x / 20, qtree.y / 20, qtree.width / 20, qtree.height / 20);
|
|
var nodes = qtree.nodes;
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
renderQuadTree(ctx, nodes[i]);
|
|
}
|
|
}
|
|
var renderingTerminated = false;
|
|
var samplesLeftPlusOne = 0;
|
|
function triggerSampling(count) {
|
|
samplesLeftPlusOne = -count - 1;
|
|
}
|
|
function sampleStart() {
|
|
if (!samplesLeftPlusOne) {
|
|
return;
|
|
}
|
|
if (samplesLeftPlusOne < 0) {
|
|
console.profile('Sample');
|
|
samplesLeftPlusOne *= -1;
|
|
}
|
|
if (samplesLeftPlusOne > 0) {
|
|
console.info('Sampling Frame: ' + (samplesLeftPlusOne - 1));
|
|
}
|
|
}
|
|
function sampleEnd() {
|
|
if (!samplesLeftPlusOne) {
|
|
return;
|
|
}
|
|
samplesLeftPlusOne--;
|
|
if (samplesLeftPlusOne === 1) {
|
|
console.profileEnd('Sample');
|
|
}
|
|
}
|
|
var timeline;
|
|
var hudTimeline;
|
|
function timelineEnter(name) {
|
|
timeline && timeline.enter(name);
|
|
hudTimeline && hudTimeline.enter(name);
|
|
}
|
|
function timelineLeave(name) {
|
|
timeline && timeline.leave(name);
|
|
hudTimeline && hudTimeline.leave(name);
|
|
}
|
|
function timelineWrapBroadcastMessage(domain, message) {
|
|
timelineEnter(message);
|
|
domain.broadcastMessage(message);
|
|
timelineLeave(message);
|
|
}
|
|
function initializeHUD(stage, parentCanvas) {
|
|
var canvas = document.createElement('canvas');
|
|
var canvasContainer = document.createElement('div');
|
|
canvasContainer.appendChild(canvas);
|
|
canvasContainer.style.position = 'absolute';
|
|
canvasContainer.style.top = '0px';
|
|
canvasContainer.style.left = '0px';
|
|
canvasContainer.style.width = '100%';
|
|
canvasContainer.style.height = '150px';
|
|
canvasContainer.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
|
|
canvasContainer.style.pointerEvents = 'none';
|
|
parentCanvas.parentElement.appendChild(canvasContainer);
|
|
hudTimeline = new Timeline(canvas);
|
|
hudTimeline.setFrameRate(stage._frameRate);
|
|
hudTimeline.refreshEvery(10);
|
|
}
|
|
function createRenderDummyBalls(ctx, stage) {
|
|
var dummyBalls;
|
|
var radius = 10;
|
|
var speed = 1;
|
|
var m = stage._concatenatedTransform;
|
|
var scaleX = m.a, scaleY = m.d;
|
|
dummyBalls = [];
|
|
for (var i = 0; i < 10; i++) {
|
|
dummyBalls.push({
|
|
position: {
|
|
x: radius + Math.random() * ((ctx.canvas.width - 2 * radius) / scaleX),
|
|
y: radius + Math.random() * ((ctx.canvas.height - 2 * radius) / scaleY)
|
|
},
|
|
velocity: {
|
|
x: speed * (Math.random() - 0.5),
|
|
y: speed * (Math.random() - 0.5)
|
|
}
|
|
});
|
|
}
|
|
ctx.fillStyle = 'black';
|
|
ctx.lineWidth = 2;
|
|
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
return function renderDummyBalls() {
|
|
ctx.fillStyle = 'black';
|
|
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
ctx.strokeStyle = 'green';
|
|
dummyBalls.forEach(function (ball) {
|
|
var position = ball.position;
|
|
var velocity = ball.velocity;
|
|
ctx.beginPath();
|
|
ctx.arc(position.x, position.y, radius, 0, Math.PI * 2, true);
|
|
ctx.stroke();
|
|
var x = position.x + velocity.x;
|
|
var y = position.y + velocity.y;
|
|
if (x < radius || x > ctx.canvas.width / scaleX - radius) {
|
|
velocity.x *= -1;
|
|
}
|
|
if (y < radius || y > ctx.canvas.height / scaleY - radius) {
|
|
velocity.y *= -1;
|
|
}
|
|
position.x += velocity.x;
|
|
position.y += velocity.y;
|
|
});
|
|
};
|
|
}
|
|
function renderStage(stage, ctx, events) {
|
|
var frameWidth, frameHeight;
|
|
if (!timeline && hud.value) {
|
|
initializeHUD(stage, ctx.canvas);
|
|
}
|
|
function updateRenderTransform() {
|
|
frameWidth = ctx.canvas.width;
|
|
frameHeight = ctx.canvas.height;
|
|
var scaleX = frameWidth / stage._stageWidth * 20;
|
|
var scaleY = frameHeight / stage._stageHeight * 20;
|
|
switch (stage._scaleMode) {
|
|
case 'exactFit':
|
|
break;
|
|
case 'noBorder':
|
|
if (scaleX > scaleY) {
|
|
scaleY = scaleX;
|
|
} else {
|
|
scaleX = scaleY;
|
|
}
|
|
break;
|
|
case 'noScale':
|
|
var pixelRatio = ctx.canvas._pixelRatio || 1;
|
|
scaleX = pixelRatio;
|
|
scaleY = pixelRatio;
|
|
break;
|
|
case 'showAll':
|
|
if (scaleX < scaleY) {
|
|
scaleY = scaleX;
|
|
} else {
|
|
scaleX = scaleY;
|
|
}
|
|
break;
|
|
}
|
|
var align = stage._align;
|
|
var offsetX, offsetY;
|
|
if (align.indexOf('L') >= 0) {
|
|
offsetX = 0;
|
|
} else if (align.indexOf('R') >= 0) {
|
|
offsetX = frameWidth - scaleX * stage._stageWidth / 20;
|
|
} else {
|
|
offsetX = (frameWidth - scaleX * stage._stageWidth / 20) / 2;
|
|
}
|
|
if (align.indexOf('T') >= 0) {
|
|
offsetY = 0;
|
|
} else if (align.indexOf('B') >= 0) {
|
|
offsetY = frameHeight - scaleY * stage._stageHeight / 20;
|
|
} else {
|
|
offsetY = (frameHeight - scaleY * stage._stageHeight / 20) / 2;
|
|
}
|
|
ctx.setTransform(scaleX, 0, 0, scaleY, offsetX, offsetY);
|
|
var m = stage._concatenatedTransform;
|
|
m.a = scaleX;
|
|
m.d = scaleY;
|
|
m.tx = offsetX * 20;
|
|
m.ty = offsetY * 20;
|
|
}
|
|
updateRenderTransform();
|
|
var frameScheduler = new FrameScheduler();
|
|
stage._frameScheduler = frameScheduler;
|
|
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || window.setTimeout;
|
|
var renderDummyBalls = dummyAnimation.value && createRenderDummyBalls(ctx, stage);
|
|
console.timeEnd('Initialize Renderer');
|
|
console.timeEnd('Total');
|
|
var firstRun = true;
|
|
var frameCount = 0;
|
|
var frameFPSAverage = new Shumway.Metrics.Average(120);
|
|
var frameRequested = true;
|
|
function drawFrame(renderFrame, repaint) {
|
|
sampleStart();
|
|
var refreshStage = false;
|
|
if (stage._invalid) {
|
|
updateRenderTransform();
|
|
stage._invalid = false;
|
|
refreshStage = true;
|
|
}
|
|
var mouseMoved = false;
|
|
if (stage._mouseMoved) {
|
|
stage._mouseMoved = false;
|
|
mouseMoved = stage._mouseOver;
|
|
} else {
|
|
stage._handleMouseButtons();
|
|
}
|
|
if (renderFrame || refreshStage || mouseMoved) {
|
|
FrameCounter.clear();
|
|
var frameStartTime = performance.now();
|
|
timelineEnter('frame');
|
|
traceRenderer.value && appendToFrameTerminal('Begin Frame #' + frameCount++, 'purple');
|
|
var domain = avm2.systemDomain;
|
|
if (renderFrame) {
|
|
timelineEnter('events');
|
|
if (firstRun) {
|
|
firstRun = false;
|
|
} else {
|
|
enableAdvanceFrame.value && timelineWrapBroadcastMessage(domain, 'advanceFrame');
|
|
enableEnterFrame.value && timelineWrapBroadcastMessage(domain, 'enterFrame');
|
|
enableConstructChildren.value && timelineWrapBroadcastMessage(domain, 'constructChildren');
|
|
}
|
|
timelineWrapBroadcastMessage(domain, 'frameConstructed');
|
|
timelineWrapBroadcastMessage(domain, 'executeFrame');
|
|
timelineWrapBroadcastMessage(domain, 'exitFrame');
|
|
timelineLeave('events');
|
|
}
|
|
if (stage._deferRenderEvent) {
|
|
stage._deferRenderEvent = false;
|
|
domain.broadcastMessage('render', 'render');
|
|
}
|
|
var drawEnabled = isCanvasVisible(ctx.canvas) && (refreshStage || renderFrame) && (frameRequested || repaint || !skipFrameDraw.value);
|
|
if (drawEnabled && !repaint && skipFrameDraw.value && frameScheduler.shallSkipDraw) {
|
|
drawEnabled = false;
|
|
frameScheduler.skipDraw();
|
|
traceRenderer.value && appendToFrameTerminal('Skip Frame Draw', 'red');
|
|
}
|
|
if (drawEnabled) {
|
|
frameScheduler.startDraw();
|
|
var invalidPath = null;
|
|
traceRenderer.value && frameWriter.enter('> Invalidation');
|
|
timelineEnter('invalidate');
|
|
invalidPath = stage._processInvalidations(refreshStage);
|
|
timelineLeave('invalidate');
|
|
traceRenderer.value && frameWriter.leave('< Invalidation');
|
|
if (!disableRenderVisitor.value && !invalidPath.isEmpty) {
|
|
timelineEnter('render');
|
|
traceRenderer.value && frameWriter.enter('> Rendering');
|
|
new RenderVisitor(stage, ctx, invalidPath, refreshStage).start();
|
|
traceRenderer.value && frameWriter.leave('< Rendering');
|
|
timelineLeave('render');
|
|
}
|
|
if (showQuadTree.value) {
|
|
ctx.strokeStyle = 'green';
|
|
renderQuadTree(ctx, stage._qtree);
|
|
}
|
|
if (invalidPath && !refreshStage && showRedrawRegions.value) {
|
|
ctx.strokeStyle = 'red';
|
|
invalidPath.draw(ctx);
|
|
ctx.stroke();
|
|
}
|
|
frameScheduler.endDraw();
|
|
}
|
|
if (mouseMoved && !disableMouseVisitor.value) {
|
|
renderFrame && timelineEnter('mouse');
|
|
traceRenderer.value && frameWriter.enter('> Mouse Handling');
|
|
stage._handleMouse();
|
|
traceRenderer.value && frameWriter.leave('< Mouse Handling');
|
|
renderFrame && timelineLeave('mouse');
|
|
ctx.canvas.style.cursor = stage._cursor;
|
|
}
|
|
if (traceRenderer.value) {
|
|
frameWriter.enter('> Frame Counters');
|
|
for (var name in FrameCounter.counts) {
|
|
frameWriter.writeLn(name + ': ' + FrameCounter.counts[name]);
|
|
}
|
|
frameWriter.leave('< Frame Counters');
|
|
var frameElapsedTime = performance.now() - frameStartTime;
|
|
var frameFPS = 1000 / frameElapsedTime;
|
|
frameFPSAverage.push(frameFPS);
|
|
traceRenderer.value && appendToFrameTerminal('End Frame Time: ' + frameElapsedTime.toFixed(2) + ' (' + frameFPS.toFixed(2) + ' fps, ' + frameFPSAverage.average().toFixed(2) + ' average fps)', 'purple');
|
|
}
|
|
timelineLeave('frame');
|
|
} else {
|
|
traceRenderer.value && appendToFrameTerminal('Skip Frame', 'black');
|
|
}
|
|
sampleEnd();
|
|
}
|
|
(function draw() {
|
|
var renderFrame = true;
|
|
if (events.onBeforeFrame) {
|
|
var e = {
|
|
cancel: false
|
|
};
|
|
events.onBeforeFrame(e);
|
|
renderFrame = !e.cancel;
|
|
}
|
|
if (renderDummyBalls) {
|
|
if (renderFrame) {
|
|
renderDummyBalls();
|
|
events.onAfterFrame && events.onAfterFrame();
|
|
}
|
|
setTimeout(draw);
|
|
return;
|
|
}
|
|
frameScheduler.startFrame(stage._frameRate);
|
|
drawFrame(renderFrame, false);
|
|
frameScheduler.endFrame();
|
|
frameRequested = false;
|
|
if (!frameScheduler.isOnTime) {
|
|
traceRenderer.value && appendToFrameTerminal('Frame Is Late', 'red');
|
|
}
|
|
if (renderFrame && events.onAfterFrame) {
|
|
events.onAfterFrame();
|
|
}
|
|
if (renderingTerminated) {
|
|
if (events.onTerminated) {
|
|
events.onTerminated();
|
|
}
|
|
return;
|
|
}
|
|
setTimeout(draw, turboMode.value ? 0 : frameScheduler.nextFrameIn);
|
|
}());
|
|
(function frame() {
|
|
if (renderingTerminated) {
|
|
return;
|
|
}
|
|
frameRequested = true;
|
|
if ((stage._invalid || stage._mouseMoved) && !renderDummyBalls) {
|
|
drawFrame(false, true);
|
|
}
|
|
requestAnimationFrame(frame);
|
|
}());
|
|
}
|
|
var FrameScheduler = function () {
|
|
var STATS_TO_REMEMBER = 50;
|
|
var MAX_DRAWS_TO_SKIP = 2;
|
|
var INTERVAL_PADDING_MS = 4;
|
|
var SPEED_ADJUST_RATE = 0.9;
|
|
function FrameScheduler() {
|
|
this._drawStats = [];
|
|
this._drawStatsSum = 0;
|
|
this._drawStarted = 0;
|
|
this._drawsSkipped = 0;
|
|
this._expectedNextFrameAt = performance.now();
|
|
this._onTime = true;
|
|
this._trackDelta = false;
|
|
this._delta = 0;
|
|
this._onTimeDelta = 0;
|
|
}
|
|
FrameScheduler.prototype = {
|
|
get shallSkipDraw() {
|
|
if (this._drawsSkipped >= MAX_DRAWS_TO_SKIP) {
|
|
return false;
|
|
}
|
|
var averageDraw = this._drawStats.length < STATS_TO_REMEMBER ? 0 : this._drawStatsSum / this._drawStats.length;
|
|
var estimatedDrawEnd = performance.now() + averageDraw;
|
|
return estimatedDrawEnd + INTERVAL_PADDING_MS > this._expectedNextFrameAt;
|
|
},
|
|
get nextFrameIn() {
|
|
return Math.max(0, this._expectedNextFrameAt - performance.now());
|
|
},
|
|
get isOnTime() {
|
|
return this._onTime;
|
|
},
|
|
startFrame: function (frameRate) {
|
|
var interval = 1000 / frameRate;
|
|
var adjustedInterval = interval;
|
|
var delta = this._onTimeDelta + this._delta;
|
|
if (delta !== 0) {
|
|
if (delta < 0) {
|
|
adjustedInterval *= SPEED_ADJUST_RATE;
|
|
} else if (delta > 0) {
|
|
adjustedInterval /= SPEED_ADJUST_RATE;
|
|
}
|
|
this._onTimeDelta += interval - adjustedInterval;
|
|
}
|
|
this._expectedNextFrameAt += adjustedInterval;
|
|
this._onTime = true;
|
|
},
|
|
endFrame: function () {
|
|
var estimatedNextFrameStart = performance.now() + INTERVAL_PADDING_MS;
|
|
if (estimatedNextFrameStart > this._expectedNextFrameAt) {
|
|
if (this._trackDelta) {
|
|
this._onTimeDelta += this._expectedNextFrameAt - estimatedNextFrameStart;
|
|
console.log(this._onTimeDelta);
|
|
}
|
|
this._expectedNextFrameAt = estimatedNextFrameStart;
|
|
this._onTime = false;
|
|
}
|
|
},
|
|
startDraw: function () {
|
|
this._drawsSkipped = 0;
|
|
this._drawStarted = performance.now();
|
|
},
|
|
endDraw: function () {
|
|
var drawTime = performance.now() - this._drawStarted;
|
|
this._drawStats.push(drawTime);
|
|
this._drawStatsSum += drawTime;
|
|
while (this._drawStats.length > STATS_TO_REMEMBER) {
|
|
this._drawStatsSum -= this._drawStats.shift();
|
|
}
|
|
},
|
|
skipDraw: function () {
|
|
this._drawsSkipped++;
|
|
},
|
|
setDelta: function (value) {
|
|
if (!this._trackDelta) {
|
|
return;
|
|
}
|
|
this._delta = value;
|
|
},
|
|
startTrackDelta: function () {
|
|
this._trackDelta = true;
|
|
},
|
|
endTrackDelta: function () {
|
|
if (!this._trackDelta) {
|
|
return;
|
|
}
|
|
this._trackDelta = false;
|
|
this._delta = 0;
|
|
this._onTimeDelta = 0;
|
|
}
|
|
};
|
|
return FrameScheduler;
|
|
}();
|
|
var tagHandler = function (global) {
|
|
function defineShape($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.id = readUi16($bytes, $stream);
|
|
var $0 = $.bbox = {};
|
|
bbox($bytes, $stream, $0, swfVersion, tagCode);
|
|
var isMorph = $.isMorph = tagCode === 46 || tagCode === 84;
|
|
if (isMorph) {
|
|
var $1 = $.bboxMorph = {};
|
|
bbox($bytes, $stream, $1, swfVersion, tagCode);
|
|
}
|
|
var hasStrokes = $.hasStrokes = tagCode === 83 || tagCode === 84;
|
|
if (hasStrokes) {
|
|
var $2 = $.strokeBbox = {};
|
|
bbox($bytes, $stream, $2, swfVersion, tagCode);
|
|
if (isMorph) {
|
|
var $3 = $.strokeBboxMorph = {};
|
|
bbox($bytes, $stream, $3, swfVersion, tagCode);
|
|
}
|
|
var reserved = readUb($bytes, $stream, 5);
|
|
$.fillWinding = readUb($bytes, $stream, 1);
|
|
$.nonScalingStrokes = readUb($bytes, $stream, 1);
|
|
$.scalingStrokes = readUb($bytes, $stream, 1);
|
|
}
|
|
if (isMorph) {
|
|
$.offsetMorph = readUi32($bytes, $stream);
|
|
morphShapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
|
|
} else {
|
|
shapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
|
|
}
|
|
return $;
|
|
}
|
|
function placeObject($bytes, $stream, $, swfVersion, tagCode) {
|
|
var flags, hasEvents, clip, hasName, hasRatio, hasCxform, hasMatrix, place;
|
|
var move, hasBackgroundColor, hasVisibility, hasImage, hasClassName, cache;
|
|
var blend, hasFilters, eoe;
|
|
$ || ($ = {});
|
|
if (tagCode > 4) {
|
|
if (tagCode > 26) {
|
|
flags = readUi16($bytes, $stream);
|
|
} else {
|
|
flags = readUi8($bytes, $stream);
|
|
}
|
|
hasEvents = $.hasEvents = flags >> 7 & 1;
|
|
clip = $.clip = flags >> 6 & 1;
|
|
hasName = $.hasName = flags >> 5 & 1;
|
|
hasRatio = $.hasRatio = flags >> 4 & 1;
|
|
hasCxform = $.hasCxform = flags >> 3 & 1;
|
|
hasMatrix = $.hasMatrix = flags >> 2 & 1;
|
|
place = $.place = flags >> 1 & 1;
|
|
move = $.move = flags & 1;
|
|
if (tagCode === 70) {
|
|
hasBackgroundColor = $.hasBackgroundColor = flags >> 15 & 1;
|
|
hasVisibility = $.hasVisibility = flags >> 14 & 1;
|
|
hasImage = $.hasImage = flags >> 12 & 1;
|
|
hasClassName = $.hasClassName = flags >> 11 & 1;
|
|
cache = $.cache = flags >> 10 & 1;
|
|
blend = $.blend = flags >> 9 & 1;
|
|
hasFilters = $.hasFilters = flags >> 8 & 1;
|
|
} else {
|
|
cache = $.cache = 0;
|
|
blend = $.blend = 0;
|
|
hasFilters = $.hasFilters = 0;
|
|
}
|
|
$.depth = readUi16($bytes, $stream);
|
|
if (hasClassName) {
|
|
$.className = readString($bytes, $stream, 0);
|
|
}
|
|
if (place) {
|
|
$.symbolId = readUi16($bytes, $stream);
|
|
}
|
|
if (hasMatrix) {
|
|
var $0 = $.matrix = {};
|
|
matrix($bytes, $stream, $0, swfVersion, tagCode);
|
|
}
|
|
if (hasCxform) {
|
|
var $1 = $.cxform = {};
|
|
cxform($bytes, $stream, $1, swfVersion, tagCode);
|
|
}
|
|
if (hasRatio) {
|
|
$.ratio = readUi16($bytes, $stream);
|
|
}
|
|
if (hasName) {
|
|
$.name = readString($bytes, $stream, 0);
|
|
}
|
|
if (clip) {
|
|
$.clipDepth = readUi16($bytes, $stream);
|
|
}
|
|
if (hasFilters) {
|
|
var count = readUi8($bytes, $stream);
|
|
var $2 = $.filters = [];
|
|
var $3 = count;
|
|
while ($3--) {
|
|
var $4 = {};
|
|
anyFilter($bytes, $stream, $4, swfVersion, tagCode);
|
|
$2.push($4);
|
|
}
|
|
}
|
|
if (blend) {
|
|
$.blendMode = readUi8($bytes, $stream);
|
|
}
|
|
if (cache) {
|
|
$.bmpCache = readUi8($bytes, $stream);
|
|
}
|
|
if (hasEvents) {
|
|
var reserved = readUi16($bytes, $stream);
|
|
if (swfVersion >= 6) {
|
|
var allFlags = readUi32($bytes, $stream);
|
|
} else {
|
|
var allFlags = readUi16($bytes, $stream);
|
|
}
|
|
var $28 = $.events = [];
|
|
do {
|
|
var $29 = {};
|
|
var temp = events($bytes, $stream, $29, swfVersion, tagCode);
|
|
eoe = temp.eoe;
|
|
$28.push($29);
|
|
} while (!eoe);
|
|
}
|
|
if (hasBackgroundColor) {
|
|
var $126 = $.backgroundColor = {};
|
|
argb($bytes, $stream, $126, swfVersion, tagCode);
|
|
}
|
|
if (hasVisibility) {
|
|
$.visibility = readUi8($bytes, $stream);
|
|
}
|
|
} else {
|
|
$.place = 1;
|
|
$.symbolId = readUi16($bytes, $stream);
|
|
$.depth = readUi16($bytes, $stream);
|
|
$.hasMatrix = 1;
|
|
var $30 = $.matrix = {};
|
|
matrix($bytes, $stream, $30, swfVersion, tagCode);
|
|
if ($stream.remaining()) {
|
|
$.hasCxform = 1;
|
|
var $31 = $.cxform = {};
|
|
cxform($bytes, $stream, $31, swfVersion, tagCode);
|
|
}
|
|
}
|
|
return $;
|
|
}
|
|
function removeObject($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
if (tagCode === 5) {
|
|
$.symbolId = readUi16($bytes, $stream);
|
|
}
|
|
$.depth = readUi16($bytes, $stream);
|
|
return $;
|
|
}
|
|
function defineImage($bytes, $stream, $, swfVersion, tagCode) {
|
|
var imgData;
|
|
$ || ($ = {});
|
|
$.id = readUi16($bytes, $stream);
|
|
if (tagCode > 21) {
|
|
var alphaDataOffset = readUi32($bytes, $stream);
|
|
if (tagCode === 90) {
|
|
$.deblock = readFixed8($bytes, $stream);
|
|
}
|
|
imgData = $.imgData = readBinary($bytes, $stream, alphaDataOffset);
|
|
$.alphaData = readBinary($bytes, $stream, 0);
|
|
} else {
|
|
imgData = $.imgData = readBinary($bytes, $stream, 0);
|
|
}
|
|
switch (imgData[0] << 8 | imgData[1]) {
|
|
case 65496:
|
|
case 65497:
|
|
$.mimeType = 'image/jpeg';
|
|
break;
|
|
case 35152:
|
|
$.mimeType = 'image/png';
|
|
break;
|
|
case 18249:
|
|
$.mimeType = 'image/gif';
|
|
break;
|
|
default:
|
|
$.mimeType = 'application/octet-stream';
|
|
}
|
|
if (tagCode === 6) {
|
|
$.incomplete = 1;
|
|
}
|
|
return $;
|
|
}
|
|
function defineButton($bytes, $stream, $, swfVersion, tagCode) {
|
|
var eob, hasFilters, count, blend;
|
|
$ || ($ = {});
|
|
$.id = readUi16($bytes, $stream);
|
|
if (tagCode == 7) {
|
|
var $0 = $.characters = [];
|
|
do {
|
|
var $1 = {};
|
|
var temp = button($bytes, $stream, $1, swfVersion, tagCode);
|
|
eob = temp.eob;
|
|
$0.push($1);
|
|
} while (!eob);
|
|
$.actionsData = readBinary($bytes, $stream, 0);
|
|
} else {
|
|
var trackFlags = readUi8($bytes, $stream);
|
|
$.trackAsMenu = trackFlags >> 7 & 1;
|
|
var actionOffset = readUi16($bytes, $stream);
|
|
var $28 = $.characters = [];
|
|
do {
|
|
var $29 = {};
|
|
var flags = readUi8($bytes, $stream);
|
|
var eob = $29.eob = !flags;
|
|
if (swfVersion >= 8) {
|
|
blend = $29.blend = flags >> 5 & 1;
|
|
hasFilters = $29.hasFilters = flags >> 4 & 1;
|
|
} else {
|
|
blend = $29.blend = 0;
|
|
hasFilters = $29.hasFilters = 0;
|
|
}
|
|
$29.stateHitTest = flags >> 3 & 1;
|
|
$29.stateDown = flags >> 2 & 1;
|
|
$29.stateOver = flags >> 1 & 1;
|
|
$29.stateUp = flags & 1;
|
|
if (!eob) {
|
|
$29.symbolId = readUi16($bytes, $stream);
|
|
$29.depth = readUi16($bytes, $stream);
|
|
var $30 = $29.matrix = {};
|
|
matrix($bytes, $stream, $30, swfVersion, tagCode);
|
|
if (tagCode === 34) {
|
|
var $31 = $29.cxform = {};
|
|
cxform($bytes, $stream, $31, swfVersion, tagCode);
|
|
}
|
|
if (hasFilters) {
|
|
var count = readUi8($bytes, $stream);
|
|
var $2 = $.filters = [];
|
|
var $3 = count;
|
|
while ($3--) {
|
|
var $4 = {};
|
|
anyFilter($bytes, $stream, $4, swfVersion, tagCode);
|
|
$2.push($4);
|
|
}
|
|
}
|
|
if (blend) {
|
|
$29.blendMode = readUi8($bytes, $stream);
|
|
}
|
|
}
|
|
$28.push($29);
|
|
} while (!eob);
|
|
if (!(!actionOffset)) {
|
|
var $56 = $.buttonActions = [];
|
|
do {
|
|
var $57 = {};
|
|
buttonCondAction($bytes, $stream, $57, swfVersion, tagCode);
|
|
$56.push($57);
|
|
} while ($stream.remaining() > 0);
|
|
}
|
|
}
|
|
return $;
|
|
}
|
|
function defineJPEGTables($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.id = 0;
|
|
$.imgData = readBinary($bytes, $stream, 0);
|
|
$.mimeType = 'application/octet-stream';
|
|
return $;
|
|
}
|
|
function setBackgroundColor($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
var $0 = $.color = {};
|
|
rgb($bytes, $stream, $0, swfVersion, tagCode);
|
|
return $;
|
|
}
|
|
function defineBinaryData($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.id = readUi16($bytes, $stream);
|
|
var reserved = readUi32($bytes, $stream);
|
|
$.data = readBinary($bytes, $stream, 0);
|
|
return $;
|
|
}
|
|
function defineFont($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.id = readUi16($bytes, $stream);
|
|
var firstOffset = readUi16($bytes, $stream);
|
|
var glyphCount = $.glyphCount = firstOffset / 2;
|
|
var restOffsets = [];
|
|
var $0 = glyphCount - 1;
|
|
while ($0--) {
|
|
restOffsets.push(readUi16($bytes, $stream));
|
|
}
|
|
$.offsets = [
|
|
firstOffset
|
|
].concat(restOffsets);
|
|
var $1 = $.glyphs = [];
|
|
var $2 = glyphCount;
|
|
while ($2--) {
|
|
var $3 = {};
|
|
shape($bytes, $stream, $3, swfVersion, tagCode);
|
|
$1.push($3);
|
|
}
|
|
return $;
|
|
}
|
|
function defineLabel($bytes, $stream, $, swfVersion, tagCode) {
|
|
var eot;
|
|
$ || ($ = {});
|
|
$.id = readUi16($bytes, $stream);
|
|
var $0 = $.bbox = {};
|
|
bbox($bytes, $stream, $0, swfVersion, tagCode);
|
|
var $1 = $.matrix = {};
|
|
matrix($bytes, $stream, $1, swfVersion, tagCode);
|
|
var glyphBits = $.glyphBits = readUi8($bytes, $stream);
|
|
var advanceBits = $.advanceBits = readUi8($bytes, $stream);
|
|
var $2 = $.records = [];
|
|
do {
|
|
var $3 = {};
|
|
var temp = textRecord($bytes, $stream, $3, swfVersion, tagCode, glyphBits, advanceBits);
|
|
eot = temp.eot;
|
|
$2.push($3);
|
|
} while (!eot);
|
|
return $;
|
|
}
|
|
function doAction($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
if (tagCode === 59) {
|
|
$.spriteId = readUi16($bytes, $stream);
|
|
}
|
|
$.actionsData = readBinary($bytes, $stream, 0);
|
|
return $;
|
|
}
|
|
function defineSound($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.id = readUi16($bytes, $stream);
|
|
var soundFlags = readUi8($bytes, $stream);
|
|
$.soundFormat = soundFlags >> 4 & 15;
|
|
$.soundRate = soundFlags >> 2 & 3;
|
|
$.soundSize = soundFlags >> 1 & 1;
|
|
$.soundType = soundFlags & 1;
|
|
$.samplesCount = readUi32($bytes, $stream);
|
|
$.soundData = readBinary($bytes, $stream, 0);
|
|
return $;
|
|
}
|
|
function startSound($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
if (tagCode == 15) {
|
|
$.soundId = readUi16($bytes, $stream);
|
|
}
|
|
if (tagCode == 89) {
|
|
$.soundClassName = readString($bytes, $stream, 0);
|
|
}
|
|
var $0 = $.soundInfo = {};
|
|
soundInfo($bytes, $stream, $0, swfVersion, tagCode);
|
|
return $;
|
|
}
|
|
function soundStreamHead($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
var playbackFlags = readUi8($bytes, $stream);
|
|
$.playbackRate = playbackFlags >> 2 & 3;
|
|
$.playbackSize = playbackFlags >> 1 & 1;
|
|
$.playbackType = playbackFlags & 1;
|
|
var streamFlags = readUi8($bytes, $stream);
|
|
var streamCompression = $.streamCompression = streamFlags >> 4 & 15;
|
|
$.streamRate = streamFlags >> 2 & 3;
|
|
$.streamSize = streamFlags >> 1 & 1;
|
|
$.streamType = streamFlags & 1;
|
|
$.samplesCount = readUi32($bytes, $stream);
|
|
if (streamCompression == 2) {
|
|
$.latencySeek = readSi16($bytes, $stream);
|
|
}
|
|
return $;
|
|
}
|
|
function soundStreamBlock($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.data = readBinary($bytes, $stream, 0);
|
|
return $;
|
|
}
|
|
function defineBitmap($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.id = readUi16($bytes, $stream);
|
|
var format = $.format = readUi8($bytes, $stream);
|
|
$.width = readUi16($bytes, $stream);
|
|
$.height = readUi16($bytes, $stream);
|
|
$.hasAlpha = tagCode === 36;
|
|
if (format === 3) {
|
|
$.colorTableSize = readUi8($bytes, $stream);
|
|
}
|
|
$.bmpData = readBinary($bytes, $stream, 0);
|
|
return $;
|
|
}
|
|
function defineText($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.id = readUi16($bytes, $stream);
|
|
var $0 = $.bbox = {};
|
|
bbox($bytes, $stream, $0, swfVersion, tagCode);
|
|
var flags = readUi16($bytes, $stream);
|
|
var hasText = $.hasText = flags >> 7 & 1;
|
|
$.wordWrap = flags >> 6 & 1;
|
|
$.multiline = flags >> 5 & 1;
|
|
$.password = flags >> 4 & 1;
|
|
$.readonly = flags >> 3 & 1;
|
|
var hasColor = $.hasColor = flags >> 2 & 1;
|
|
var hasMaxLength = $.hasMaxLength = flags >> 1 & 1;
|
|
var hasFont = $.hasFont = flags & 1;
|
|
var hasFontClass = $.hasFontClass = flags >> 15 & 1;
|
|
$.autoSize = flags >> 14 & 1;
|
|
var hasLayout = $.hasLayout = flags >> 13 & 1;
|
|
$.noSelect = flags >> 12 & 1;
|
|
$.border = flags >> 11 & 1;
|
|
$.wasStatic = flags >> 10 & 1;
|
|
$.html = flags >> 9 & 1;
|
|
$.useOutlines = flags >> 8 & 1;
|
|
if (hasFont) {
|
|
$.fontId = readUi16($bytes, $stream);
|
|
}
|
|
if (hasFontClass) {
|
|
$.fontClass = readString($bytes, $stream, 0);
|
|
}
|
|
if (hasFont) {
|
|
$.fontHeight = readUi16($bytes, $stream);
|
|
}
|
|
if (hasColor) {
|
|
var $1 = $.color = {};
|
|
rgba($bytes, $stream, $1, swfVersion, tagCode);
|
|
}
|
|
if (hasMaxLength) {
|
|
$.maxLength = readUi16($bytes, $stream);
|
|
}
|
|
if (hasLayout) {
|
|
$.align = readUi8($bytes, $stream);
|
|
$.leftMargin = readUi16($bytes, $stream);
|
|
$.rightMargin = readUi16($bytes, $stream);
|
|
$.indent = readSi16($bytes, $stream);
|
|
$.leading = readSi16($bytes, $stream);
|
|
}
|
|
$.variableName = readString($bytes, $stream, 0);
|
|
if (hasText) {
|
|
$.initialText = readString($bytes, $stream, 0);
|
|
}
|
|
return $;
|
|
}
|
|
function frameLabel($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.name = readString($bytes, $stream, 0);
|
|
return $;
|
|
}
|
|
function defineFont2($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.id = readUi16($bytes, $stream);
|
|
var hasLayout = $.hasLayout = readUb($bytes, $stream, 1);
|
|
if (swfVersion > 5) {
|
|
$.shiftJis = readUb($bytes, $stream, 1);
|
|
} else {
|
|
var reserved = readUb($bytes, $stream, 1);
|
|
}
|
|
$.smallText = readUb($bytes, $stream, 1);
|
|
$.ansi = readUb($bytes, $stream, 1);
|
|
var wideOffset = $.wideOffset = readUb($bytes, $stream, 1);
|
|
var wide = $.wide = readUb($bytes, $stream, 1);
|
|
$.italic = readUb($bytes, $stream, 1);
|
|
$.bold = readUb($bytes, $stream, 1);
|
|
if (swfVersion > 5) {
|
|
$.language = readUi8($bytes, $stream);
|
|
} else {
|
|
var reserved = readUi8($bytes, $stream);
|
|
$.language = 0;
|
|
}
|
|
var nameLength = readUi8($bytes, $stream);
|
|
$.name = readString($bytes, $stream, nameLength);
|
|
if (tagCode === 75) {
|
|
$.resolution = 20;
|
|
}
|
|
var glyphCount = $.glyphCount = readUi16($bytes, $stream);
|
|
if (wideOffset) {
|
|
var $0 = $.offsets = [];
|
|
var $1 = glyphCount;
|
|
while ($1--) {
|
|
$0.push(readUi32($bytes, $stream));
|
|
}
|
|
$.mapOffset = readUi32($bytes, $stream);
|
|
} else {
|
|
var $2 = $.offsets = [];
|
|
var $3 = glyphCount;
|
|
while ($3--) {
|
|
$2.push(readUi16($bytes, $stream));
|
|
}
|
|
$.mapOffset = readUi16($bytes, $stream);
|
|
}
|
|
var $4 = $.glyphs = [];
|
|
var $5 = glyphCount;
|
|
while ($5--) {
|
|
var $6 = {};
|
|
shape($bytes, $stream, $6, swfVersion, tagCode);
|
|
$4.push($6);
|
|
}
|
|
if (wide) {
|
|
var $47 = $.codes = [];
|
|
var $48 = glyphCount;
|
|
while ($48--) {
|
|
$47.push(readUi16($bytes, $stream));
|
|
}
|
|
} else {
|
|
var $49 = $.codes = [];
|
|
var $50 = glyphCount;
|
|
while ($50--) {
|
|
$49.push(readUi8($bytes, $stream));
|
|
}
|
|
}
|
|
if (hasLayout) {
|
|
$.ascent = readUi16($bytes, $stream);
|
|
$.descent = readUi16($bytes, $stream);
|
|
$.leading = readSi16($bytes, $stream);
|
|
var $51 = $.advance = [];
|
|
var $52 = glyphCount;
|
|
while ($52--) {
|
|
$51.push(readSi16($bytes, $stream));
|
|
}
|
|
var $53 = $.bbox = [];
|
|
var $54 = glyphCount;
|
|
while ($54--) {
|
|
var $55 = {};
|
|
bbox($bytes, $stream, $55, swfVersion, tagCode);
|
|
$53.push($55);
|
|
}
|
|
var kerningCount = readUi16($bytes, $stream);
|
|
var $56 = $.kerning = [];
|
|
var $57 = kerningCount;
|
|
while ($57--) {
|
|
var $58 = {};
|
|
kerning($bytes, $stream, $58, swfVersion, tagCode, wide);
|
|
$56.push($58);
|
|
}
|
|
}
|
|
return $;
|
|
}
|
|
function fileAttributes($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
var reserved = readUb($bytes, $stream, 1);
|
|
$.useDirectBlit = readUb($bytes, $stream, 1);
|
|
$.useGpu = readUb($bytes, $stream, 1);
|
|
$.hasMetadata = readUb($bytes, $stream, 1);
|
|
$.doAbc = readUb($bytes, $stream, 1);
|
|
$.noCrossDomainCaching = readUb($bytes, $stream, 1);
|
|
$.relativeUrls = readUb($bytes, $stream, 1);
|
|
$.network = readUb($bytes, $stream, 1);
|
|
var pad = readUb($bytes, $stream, 24);
|
|
return $;
|
|
}
|
|
function doABC($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
if (tagCode === 82) {
|
|
$.flags = readUi32($bytes, $stream);
|
|
} else {
|
|
$.flags = 0;
|
|
}
|
|
if (tagCode === 82) {
|
|
$.name = readString($bytes, $stream, 0);
|
|
} else {
|
|
$.name = '';
|
|
}
|
|
$.data = readBinary($bytes, $stream, 0);
|
|
return $;
|
|
}
|
|
function exportAssets($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
var exportsCount = readUi16($bytes, $stream);
|
|
var $0 = $.exports = [];
|
|
var $1 = exportsCount;
|
|
while ($1--) {
|
|
var $2 = {};
|
|
$2.symbolId = readUi16($bytes, $stream);
|
|
$2.className = readString($bytes, $stream, 0);
|
|
$0.push($2);
|
|
}
|
|
return $;
|
|
}
|
|
function symbolClass($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
var symbolCount = readUi16($bytes, $stream);
|
|
var $0 = $.exports = [];
|
|
var $1 = symbolCount;
|
|
while ($1--) {
|
|
var $2 = {};
|
|
$2.symbolId = readUi16($bytes, $stream);
|
|
$2.className = readString($bytes, $stream, 0);
|
|
$0.push($2);
|
|
}
|
|
return $;
|
|
}
|
|
function defineScalingGrid($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
$.symbolId = readUi16($bytes, $stream);
|
|
var $0 = $.splitter = {};
|
|
bbox($bytes, $stream, $0, swfVersion, tagCode);
|
|
return $;
|
|
}
|
|
function defineScene($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
var sceneCount = readEncodedU32($bytes, $stream);
|
|
var $0 = $.scenes = [];
|
|
var $1 = sceneCount;
|
|
while ($1--) {
|
|
var $2 = {};
|
|
$2.offset = readEncodedU32($bytes, $stream);
|
|
$2.name = readString($bytes, $stream, 0);
|
|
$0.push($2);
|
|
}
|
|
var labelCount = readEncodedU32($bytes, $stream);
|
|
var $3 = $.labels = [];
|
|
var $4 = labelCount;
|
|
while ($4--) {
|
|
var $5 = {};
|
|
$5.frame = readEncodedU32($bytes, $stream);
|
|
$5.name = readString($bytes, $stream, 0);
|
|
$3.push($5);
|
|
}
|
|
return $;
|
|
}
|
|
function bbox($bytes, $stream, $, swfVersion, tagCode) {
|
|
align($bytes, $stream);
|
|
var bits = readUb($bytes, $stream, 5);
|
|
var xMin = readSb($bytes, $stream, bits);
|
|
var xMax = readSb($bytes, $stream, bits);
|
|
var yMin = readSb($bytes, $stream, bits);
|
|
var yMax = readSb($bytes, $stream, bits);
|
|
$.xMin = xMin;
|
|
$.xMax = xMax;
|
|
$.yMin = yMin;
|
|
$.yMax = yMax;
|
|
align($bytes, $stream);
|
|
}
|
|
function rgb($bytes, $stream, $, swfVersion, tagCode) {
|
|
$.red = readUi8($bytes, $stream);
|
|
$.green = readUi8($bytes, $stream);
|
|
$.blue = readUi8($bytes, $stream);
|
|
$.alpha = 255;
|
|
return;
|
|
}
|
|
function rgba($bytes, $stream, $, swfVersion, tagCode) {
|
|
$.red = readUi8($bytes, $stream);
|
|
$.green = readUi8($bytes, $stream);
|
|
$.blue = readUi8($bytes, $stream);
|
|
$.alpha = readUi8($bytes, $stream);
|
|
return;
|
|
}
|
|
function argb($bytes, $stream, $, swfVersion, tagCode) {
|
|
$.alpha = readUi8($bytes, $stream);
|
|
$.red = readUi8($bytes, $stream);
|
|
$.green = readUi8($bytes, $stream);
|
|
$.blue = readUi8($bytes, $stream);
|
|
}
|
|
function fillSolid($bytes, $stream, $, swfVersion, tagCode, isMorph) {
|
|
if (tagCode > 22 || isMorph) {
|
|
var $125 = $.color = {};
|
|
rgba($bytes, $stream, $125, swfVersion, tagCode);
|
|
} else {
|
|
var $126 = $.color = {};
|
|
rgb($bytes, $stream, $126, swfVersion, tagCode);
|
|
}
|
|
if (isMorph) {
|
|
var $127 = $.colorMorph = {};
|
|
rgba($bytes, $stream, $127, swfVersion, tagCode);
|
|
}
|
|
return;
|
|
}
|
|
function matrix($bytes, $stream, $, swfVersion, tagCode) {
|
|
align($bytes, $stream);
|
|
var hasScale = readUb($bytes, $stream, 1);
|
|
if (hasScale) {
|
|
var bits = readUb($bytes, $stream, 5);
|
|
$.a = readFb($bytes, $stream, bits);
|
|
$.d = readFb($bytes, $stream, bits);
|
|
} else {
|
|
$.a = 1;
|
|
$.d = 1;
|
|
}
|
|
var hasRotate = readUb($bytes, $stream, 1);
|
|
if (hasRotate) {
|
|
var bits = readUb($bytes, $stream, 5);
|
|
$.b = readFb($bytes, $stream, bits);
|
|
$.c = readFb($bytes, $stream, bits);
|
|
} else {
|
|
$.b = 0;
|
|
$.c = 0;
|
|
}
|
|
var bits = readUb($bytes, $stream, 5);
|
|
var e = readSb($bytes, $stream, bits);
|
|
var f = readSb($bytes, $stream, bits);
|
|
$.tx = e;
|
|
$.ty = f;
|
|
align($bytes, $stream);
|
|
}
|
|
function cxform($bytes, $stream, $, swfVersion, tagCode) {
|
|
align($bytes, $stream);
|
|
var hasOffsets = readUb($bytes, $stream, 1);
|
|
var hasMultipliers = readUb($bytes, $stream, 1);
|
|
var bits = readUb($bytes, $stream, 4);
|
|
if (hasMultipliers) {
|
|
$.redMultiplier = readSb($bytes, $stream, bits);
|
|
$.greenMultiplier = readSb($bytes, $stream, bits);
|
|
$.blueMultiplier = readSb($bytes, $stream, bits);
|
|
if (tagCode > 4) {
|
|
$.alphaMultiplier = readSb($bytes, $stream, bits);
|
|
} else {
|
|
$.alphaMultiplier = 256;
|
|
}
|
|
} else {
|
|
$.redMultiplier = 256;
|
|
$.greenMultiplier = 256;
|
|
$.blueMultiplier = 256;
|
|
$.alphaMultiplier = 256;
|
|
}
|
|
if (hasOffsets) {
|
|
$.redOffset = readSb($bytes, $stream, bits);
|
|
$.greenOffset = readSb($bytes, $stream, bits);
|
|
$.blueOffset = readSb($bytes, $stream, bits);
|
|
if (tagCode > 4) {
|
|
$.alphaOffset = readSb($bytes, $stream, bits);
|
|
} else {
|
|
$.alphaOffset = 0;
|
|
}
|
|
} else {
|
|
$.redOffset = 0;
|
|
$.greenOffset = 0;
|
|
$.blueOffset = 0;
|
|
$.alphaOffset = 0;
|
|
}
|
|
align($bytes, $stream);
|
|
}
|
|
function fillGradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type) {
|
|
var $128 = $.matrix = {};
|
|
matrix($bytes, $stream, $128, swfVersion, tagCode);
|
|
if (isMorph) {
|
|
var $129 = $.matrixMorph = {};
|
|
matrix($bytes, $stream, $129, swfVersion, tagCode);
|
|
}
|
|
gradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type);
|
|
}
|
|
function gradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type) {
|
|
if (tagCode === 83) {
|
|
$.spreadMode = readUb($bytes, $stream, 2);
|
|
$.interpolationMode = readUb($bytes, $stream, 2);
|
|
} else {
|
|
var pad = readUb($bytes, $stream, 4);
|
|
}
|
|
var count = $.count = readUb($bytes, $stream, 4);
|
|
var $130 = $.records = [];
|
|
var $131 = count;
|
|
while ($131--) {
|
|
var $132 = {};
|
|
gradientRecord($bytes, $stream, $132, swfVersion, tagCode, isMorph);
|
|
$130.push($132);
|
|
}
|
|
if (type === 19) {
|
|
$.focalPoint = readFixed8($bytes, $stream);
|
|
if (isMorph) {
|
|
$.focalPointMorph = readFixed8($bytes, $stream);
|
|
}
|
|
}
|
|
}
|
|
function gradientRecord($bytes, $stream, $, swfVersion, tagCode, isMorph) {
|
|
$.ratio = readUi8($bytes, $stream);
|
|
if (tagCode > 22) {
|
|
var $133 = $.color = {};
|
|
rgba($bytes, $stream, $133, swfVersion, tagCode);
|
|
} else {
|
|
var $134 = $.color = {};
|
|
rgb($bytes, $stream, $134, swfVersion, tagCode);
|
|
}
|
|
if (isMorph) {
|
|
$.ratioMorph = readUi8($bytes, $stream);
|
|
var $135 = $.colorMorph = {};
|
|
rgba($bytes, $stream, $135, swfVersion, tagCode);
|
|
}
|
|
}
|
|
function morphShapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) {
|
|
var eos, bits;
|
|
var temp = styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
|
|
var lineBits = temp.lineBits;
|
|
var fillBits = temp.fillBits;
|
|
var $160 = $.records = [];
|
|
do {
|
|
var $161 = {};
|
|
var temp = shapeRecord($bytes, $stream, $161, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits);
|
|
var eos = temp.eos;
|
|
var flags = temp.flags;
|
|
var type = temp.type;
|
|
var fillBits = temp.fillBits;
|
|
var lineBits = temp.lineBits;
|
|
var bits = temp.bits;
|
|
$160.push($161);
|
|
} while (!eos);
|
|
var temp = styleBits($bytes, $stream, $, swfVersion, tagCode);
|
|
var fillBits = temp.fillBits;
|
|
var lineBits = temp.lineBits;
|
|
var $162 = $.recordsMorph = [];
|
|
do {
|
|
var $163 = {};
|
|
var temp = shapeRecord($bytes, $stream, $163, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits);
|
|
eos = temp.eos;
|
|
var flags = temp.flags;
|
|
var type = temp.type;
|
|
var fillBits = temp.fillBits;
|
|
var lineBits = temp.lineBits;
|
|
bits = temp.bits;
|
|
$162.push($163);
|
|
} while (!eos);
|
|
}
|
|
function shapeWithStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) {
|
|
var eos;
|
|
var temp = styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
|
|
var fillBits = temp.fillBits;
|
|
var lineBits = temp.lineBits;
|
|
var $160 = $.records = [];
|
|
do {
|
|
var $161 = {};
|
|
var temp = shapeRecord($bytes, $stream, $161, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits);
|
|
eos = temp.eos;
|
|
var flags = temp.flags;
|
|
var type = temp.type;
|
|
var fillBits = temp.fillBits;
|
|
var lineBits = temp.lineBits;
|
|
var bits = temp.bits;
|
|
$160.push($161);
|
|
} while (!eos);
|
|
}
|
|
function shapeRecord($bytes, $stream, $, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits) {
|
|
var type = $.type = readUb($bytes, $stream, 1);
|
|
var flags = readUb($bytes, $stream, 5);
|
|
var eos = $.eos = !(type || flags);
|
|
if (type) {
|
|
var temp = shapeRecordEdge($bytes, $stream, $, swfVersion, tagCode, flags, bits);
|
|
var bits = temp.bits;
|
|
} else {
|
|
var temp = shapeRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags, isMorph, fillBits, lineBits, hasStrokes, bits);
|
|
var fillBits = temp.fillBits;
|
|
var lineBits = temp.lineBits;
|
|
var bits = temp.bits;
|
|
}
|
|
return {
|
|
type: type,
|
|
flags: flags,
|
|
eos: eos,
|
|
fillBits: fillBits,
|
|
lineBits: lineBits,
|
|
bits: bits
|
|
};
|
|
}
|
|
function shapeRecordEdge($bytes, $stream, $, swfVersion, tagCode, flags, bits) {
|
|
var isStraight = 0, tmp = 0, bits = 0, isGeneral = 0, isVertical = 0;
|
|
isStraight = $.isStraight = flags >> 4;
|
|
tmp = flags & 15;
|
|
bits = tmp + 2;
|
|
if (isStraight) {
|
|
isGeneral = $.isGeneral = readUb($bytes, $stream, 1);
|
|
if (isGeneral) {
|
|
$.deltaX = readSb($bytes, $stream, bits);
|
|
$.deltaY = readSb($bytes, $stream, bits);
|
|
} else {
|
|
isVertical = $.isVertical = readUb($bytes, $stream, 1);
|
|
if (isVertical) {
|
|
$.deltaY = readSb($bytes, $stream, bits);
|
|
} else {
|
|
$.deltaX = readSb($bytes, $stream, bits);
|
|
}
|
|
}
|
|
} else {
|
|
$.controlDeltaX = readSb($bytes, $stream, bits);
|
|
$.controlDeltaY = readSb($bytes, $stream, bits);
|
|
$.anchorDeltaX = readSb($bytes, $stream, bits);
|
|
$.anchorDeltaY = readSb($bytes, $stream, bits);
|
|
}
|
|
return {
|
|
bits: bits
|
|
};
|
|
}
|
|
function shapeRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags, isMorph, fillBits, lineBits, hasStrokes, bits) {
|
|
var hasNewStyles = 0, hasLineStyle = 0, hasFillStyle1 = 0;
|
|
var hasFillStyle0 = 0, move = 0;
|
|
if (tagCode > 2) {
|
|
hasNewStyles = $.hasNewStyles = flags >> 4;
|
|
} else {
|
|
hasNewStyles = $.hasNewStyles = 0;
|
|
}
|
|
hasLineStyle = $.hasLineStyle = flags >> 3 & 1;
|
|
hasFillStyle1 = $.hasFillStyle1 = flags >> 2 & 1;
|
|
hasFillStyle0 = $.hasFillStyle0 = flags >> 1 & 1;
|
|
move = $.move = flags & 1;
|
|
if (move) {
|
|
bits = readUb($bytes, $stream, 5);
|
|
$.moveX = readSb($bytes, $stream, bits);
|
|
$.moveY = readSb($bytes, $stream, bits);
|
|
}
|
|
if (hasFillStyle0) {
|
|
$.fillStyle0 = readUb($bytes, $stream, fillBits);
|
|
}
|
|
if (hasFillStyle1) {
|
|
$.fillStyle1 = readUb($bytes, $stream, fillBits);
|
|
}
|
|
if (hasLineStyle) {
|
|
$.lineStyle = readUb($bytes, $stream, lineBits);
|
|
}
|
|
if (hasNewStyles) {
|
|
var temp = styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
|
|
var lineBits = temp.lineBits;
|
|
var fillBits = temp.fillBits;
|
|
}
|
|
return {
|
|
lineBits: lineBits,
|
|
fillBits: fillBits,
|
|
bits: bits
|
|
};
|
|
}
|
|
function styles($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) {
|
|
fillStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph);
|
|
lineStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes);
|
|
var temp = styleBits($bytes, $stream, $, swfVersion, tagCode);
|
|
var fillBits = temp.fillBits;
|
|
var lineBits = temp.lineBits;
|
|
return {
|
|
fillBits: fillBits,
|
|
lineBits: lineBits
|
|
};
|
|
}
|
|
function fillStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph) {
|
|
var count;
|
|
var tmp = readUi8($bytes, $stream);
|
|
if (tagCode > 2 && tmp === 255) {
|
|
count = readUi16($bytes, $stream);
|
|
} else {
|
|
count = tmp;
|
|
}
|
|
var $4 = $.fillStyles = [];
|
|
var $5 = count;
|
|
while ($5--) {
|
|
var $6 = {};
|
|
fillStyle($bytes, $stream, $6, swfVersion, tagCode, isMorph);
|
|
$4.push($6);
|
|
}
|
|
}
|
|
function lineStyleArray($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) {
|
|
var count;
|
|
var tmp = readUi8($bytes, $stream);
|
|
if (tagCode > 2 && tmp === 255) {
|
|
count = readUi16($bytes, $stream);
|
|
} else {
|
|
count = tmp;
|
|
}
|
|
var $138 = $.lineStyles = [];
|
|
var $139 = count;
|
|
while ($139--) {
|
|
var $140 = {};
|
|
lineStyle($bytes, $stream, $140, swfVersion, tagCode, isMorph, hasStrokes);
|
|
$138.push($140);
|
|
}
|
|
}
|
|
function styleBits($bytes, $stream, $, swfVersion, tagCode) {
|
|
align($bytes, $stream);
|
|
var fillBits = readUb($bytes, $stream, 4);
|
|
var lineBits = readUb($bytes, $stream, 4);
|
|
return {
|
|
fillBits: fillBits,
|
|
lineBits: lineBits
|
|
};
|
|
}
|
|
function fillStyle($bytes, $stream, $, swfVersion, tagCode, isMorph) {
|
|
var type = $.type = readUi8($bytes, $stream);
|
|
switch (type) {
|
|
case 0:
|
|
fillSolid($bytes, $stream, $, swfVersion, tagCode, isMorph);
|
|
break;
|
|
case 16:
|
|
case 18:
|
|
case 19:
|
|
fillGradient($bytes, $stream, $, swfVersion, tagCode, isMorph, type);
|
|
break;
|
|
case 64:
|
|
case 65:
|
|
case 66:
|
|
case 67:
|
|
fillBitmap($bytes, $stream, $, swfVersion, tagCode, isMorph, type);
|
|
break;
|
|
default:
|
|
}
|
|
}
|
|
function lineStyle($bytes, $stream, $, swfVersion, tagCode, isMorph, hasStrokes) {
|
|
$.width = readUi16($bytes, $stream);
|
|
if (isMorph) {
|
|
$.widthMorph = readUi16($bytes, $stream);
|
|
}
|
|
if (hasStrokes) {
|
|
align($bytes, $stream);
|
|
$.startCapStyle = readUb($bytes, $stream, 2);
|
|
var joinStyle = $.joinStyle = readUb($bytes, $stream, 2);
|
|
var hasFill = $.hasFill = readUb($bytes, $stream, 1);
|
|
$.noHscale = readUb($bytes, $stream, 1);
|
|
$.noVscale = readUb($bytes, $stream, 1);
|
|
$.pixelHinting = readUb($bytes, $stream, 1);
|
|
var reserved = readUb($bytes, $stream, 5);
|
|
$.noClose = readUb($bytes, $stream, 1);
|
|
$.endCapStyle = readUb($bytes, $stream, 2);
|
|
if (joinStyle === 2) {
|
|
$.miterLimitFactor = readFixed8($bytes, $stream);
|
|
}
|
|
if (hasFill) {
|
|
var $141 = $.fillStyle = {};
|
|
fillStyle($bytes, $stream, $141, swfVersion, tagCode, isMorph);
|
|
} else {
|
|
var $155 = $.color = {};
|
|
rgba($bytes, $stream, $155, swfVersion, tagCode);
|
|
if (isMorph) {
|
|
var $156 = $.colorMorph = {};
|
|
rgba($bytes, $stream, $156, swfVersion, tagCode);
|
|
}
|
|
}
|
|
} else {
|
|
if (tagCode > 22) {
|
|
var $157 = $.color = {};
|
|
rgba($bytes, $stream, $157, swfVersion, tagCode);
|
|
} else {
|
|
var $158 = $.color = {};
|
|
rgb($bytes, $stream, $158, swfVersion, tagCode);
|
|
}
|
|
if (isMorph) {
|
|
var $159 = $.colorMorph = {};
|
|
rgba($bytes, $stream, $159, swfVersion, tagCode);
|
|
}
|
|
}
|
|
}
|
|
function fillBitmap($bytes, $stream, $, swfVersion, tagCode, isMorph, type) {
|
|
$.bitmapId = readUi16($bytes, $stream);
|
|
var $18 = $.matrix = {};
|
|
matrix($bytes, $stream, $18, swfVersion, tagCode);
|
|
if (isMorph) {
|
|
var $19 = $.matrixMorph = {};
|
|
matrix($bytes, $stream, $19, swfVersion, tagCode);
|
|
}
|
|
$.condition = type === 64 || type === 67;
|
|
}
|
|
function filterGlow($bytes, $stream, $, swfVersion, tagCode, type) {
|
|
var count;
|
|
if (type === 4 || type === 7) {
|
|
count = readUi8($bytes, $stream);
|
|
} else {
|
|
count = 1;
|
|
}
|
|
var $5 = $.colors = [];
|
|
var $6 = count;
|
|
while ($6--) {
|
|
var $7 = {};
|
|
rgba($bytes, $stream, $7, swfVersion, tagCode);
|
|
$5.push($7);
|
|
}
|
|
if (type === 3) {
|
|
var $8 = $.higlightColor = {};
|
|
rgba($bytes, $stream, $8, swfVersion, tagCode);
|
|
}
|
|
if (type === 4 || type === 7) {
|
|
var $9 = $.ratios = [];
|
|
var $10 = count;
|
|
while ($10--) {
|
|
$9.push(readUi8($bytes, $stream));
|
|
}
|
|
}
|
|
$.blurX = readFixed($bytes, $stream);
|
|
$.blurY = readFixed($bytes, $stream);
|
|
if (type !== 2) {
|
|
$.angle = readFixed($bytes, $stream);
|
|
$.distance = readFixed($bytes, $stream);
|
|
}
|
|
$.strength = readFixed8($bytes, $stream);
|
|
$.innerShadow = readUb($bytes, $stream, 1);
|
|
$.knockout = readUb($bytes, $stream, 1);
|
|
$.compositeSource = readUb($bytes, $stream, 1);
|
|
if (type === 3) {
|
|
$.onTop = readUb($bytes, $stream, 1);
|
|
} else {
|
|
var reserved = readUb($bytes, $stream, 1);
|
|
}
|
|
if (type === 4 || type === 7) {
|
|
$.passes = readUb($bytes, $stream, 4);
|
|
} else {
|
|
var reserved = readUb($bytes, $stream, 4);
|
|
}
|
|
}
|
|
function filterBlur($bytes, $stream, $, swfVersion, tagCode) {
|
|
$.blurX = readFixed($bytes, $stream);
|
|
$.blurY = readFixed($bytes, $stream);
|
|
$.passes = readUb($bytes, $stream, 5);
|
|
var reserved = readUb($bytes, $stream, 3);
|
|
}
|
|
function filterConvolution($bytes, $stream, $, swfVersion, tagCode) {
|
|
var columns = $.columns = readUi8($bytes, $stream);
|
|
var rows = $.rows = readUi8($bytes, $stream);
|
|
$.divisor = readFloat($bytes, $stream);
|
|
$.bias = readFloat($bytes, $stream);
|
|
var $17 = $.weights = [];
|
|
var $18 = columns * rows;
|
|
while ($18--) {
|
|
$17.push(readFloat($bytes, $stream));
|
|
}
|
|
var $19 = $.defaultColor = {};
|
|
rgba($bytes, $stream, $19, swfVersion, tagCode);
|
|
var reserved = readUb($bytes, $stream, 6);
|
|
$.clamp = readUb($bytes, $stream, 1);
|
|
$.preserveAlpha = readUb($bytes, $stream, 1);
|
|
}
|
|
function filterColorMatrix($bytes, $stream, $, swfVersion, tagCode) {
|
|
var $20 = $.matrix = [];
|
|
var $21 = 20;
|
|
while ($21--) {
|
|
$20.push(readFloat($bytes, $stream));
|
|
}
|
|
}
|
|
function anyFilter($bytes, $stream, $, swfVersion, tagCode) {
|
|
var type = $.type = readUi8($bytes, $stream);
|
|
switch (type) {
|
|
case 0:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 7:
|
|
filterGlow($bytes, $stream, $, swfVersion, tagCode, type);
|
|
break;
|
|
case 1:
|
|
filterBlur($bytes, $stream, $, swfVersion, tagCode);
|
|
break;
|
|
case 5:
|
|
filterConvolution($bytes, $stream, $, swfVersion, tagCode);
|
|
break;
|
|
case 6:
|
|
filterColorMatrix($bytes, $stream, $, swfVersion, tagCode);
|
|
break;
|
|
default:
|
|
}
|
|
}
|
|
function events($bytes, $stream, $, swfVersion, tagCode) {
|
|
var flags, keyPress;
|
|
if (swfVersion >= 6) {
|
|
flags = readUi32($bytes, $stream);
|
|
} else {
|
|
flags = readUi16($bytes, $stream);
|
|
}
|
|
var eoe = $.eoe = !flags;
|
|
$.onKeyUp = flags >> 7 & 1;
|
|
$.onKeyDown = flags >> 6 & 1;
|
|
$.onMouseUp = flags >> 5 & 1;
|
|
$.onMouseDown = flags >> 4 & 1;
|
|
$.onMouseMove = flags >> 3 & 1;
|
|
$.onUnload = flags >> 2 & 1;
|
|
$.onEnterFrame = flags >> 1 & 1;
|
|
$.onLoad = flags & 1;
|
|
if (swfVersion >= 6) {
|
|
$.onDragOver = flags >> 15 & 1;
|
|
$.onRollOut = flags >> 14 & 1;
|
|
$.onRollOver = flags >> 13 & 1;
|
|
$.onReleaseOutside = flags >> 12 & 1;
|
|
$.onRelease = flags >> 11 & 1;
|
|
$.onPress = flags >> 10 & 1;
|
|
$.onInitialize = flags >> 9 & 1;
|
|
$.onData = flags >> 8 & 1;
|
|
if (swfVersion >= 7) {
|
|
$.onConstruct = flags >> 18 & 1;
|
|
} else {
|
|
$.onConstruct = 0;
|
|
}
|
|
keyPress = $.keyPress = flags >> 17 & 1;
|
|
$.onDragOut = flags >> 16 & 1;
|
|
}
|
|
if (!eoe) {
|
|
var length = $.length = readUi32($bytes, $stream);
|
|
if (keyPress) {
|
|
$.keyCode = readUi8($bytes, $stream);
|
|
}
|
|
$.actionsData = readBinary($bytes, $stream, length - (keyPress ? 1 : 0));
|
|
}
|
|
return {
|
|
eoe: eoe
|
|
};
|
|
}
|
|
function kerning($bytes, $stream, $, swfVersion, tagCode, wide) {
|
|
if (wide) {
|
|
$.code1 = readUi16($bytes, $stream);
|
|
$.code2 = readUi16($bytes, $stream);
|
|
} else {
|
|
$.code1 = readUi8($bytes, $stream);
|
|
$.code2 = readUi8($bytes, $stream);
|
|
}
|
|
$.adjustment = readUi16($bytes, $stream);
|
|
}
|
|
function textEntry($bytes, $stream, $, swfVersion, tagCode, glyphBits, advanceBits) {
|
|
$.glyphIndex = readUb($bytes, $stream, glyphBits);
|
|
$.advance = readSb($bytes, $stream, advanceBits);
|
|
}
|
|
function textRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags) {
|
|
var hasFont = $.hasFont = flags >> 3 & 1;
|
|
var hasColor = $.hasColor = flags >> 2 & 1;
|
|
var hasMoveY = $.hasMoveY = flags >> 1 & 1;
|
|
var hasMoveX = $.hasMoveX = flags & 1;
|
|
if (hasFont) {
|
|
$.fontId = readUi16($bytes, $stream);
|
|
}
|
|
if (hasColor) {
|
|
if (tagCode === 33) {
|
|
var $4 = $.color = {};
|
|
rgba($bytes, $stream, $4, swfVersion, tagCode);
|
|
} else {
|
|
var $5 = $.color = {};
|
|
rgb($bytes, $stream, $5, swfVersion, tagCode);
|
|
}
|
|
}
|
|
if (hasMoveX) {
|
|
$.moveX = readSi16($bytes, $stream);
|
|
}
|
|
if (hasMoveY) {
|
|
$.moveY = readSi16($bytes, $stream);
|
|
}
|
|
if (hasFont) {
|
|
$.fontHeight = readUi16($bytes, $stream);
|
|
}
|
|
}
|
|
function textRecord($bytes, $stream, $, swfVersion, tagCode, glyphBits, advanceBits) {
|
|
var glyphCount;
|
|
align($bytes, $stream);
|
|
var flags = readUb($bytes, $stream, 8);
|
|
var eot = $.eot = !flags;
|
|
textRecordSetup($bytes, $stream, $, swfVersion, tagCode, flags);
|
|
if (!eot) {
|
|
var tmp = readUi8($bytes, $stream);
|
|
if (swfVersion > 6) {
|
|
glyphCount = $.glyphCount = tmp;
|
|
} else {
|
|
glyphCount = $.glyphCount = tmp & 127;
|
|
}
|
|
var $6 = $.entries = [];
|
|
var $7 = glyphCount;
|
|
while ($7--) {
|
|
var $8 = {};
|
|
textEntry($bytes, $stream, $8, swfVersion, tagCode, glyphBits, advanceBits);
|
|
$6.push($8);
|
|
}
|
|
}
|
|
return {
|
|
eot: eot
|
|
};
|
|
}
|
|
function soundEnvelope($bytes, $stream, $, swfVersion, tagCode) {
|
|
$.pos44 = readUi32($bytes, $stream);
|
|
$.volumeLeft = readUi16($bytes, $stream);
|
|
$.volumeRight = readUi16($bytes, $stream);
|
|
}
|
|
function soundInfo($bytes, $stream, $, swfVersion, tagCode) {
|
|
var reserved = readUb($bytes, $stream, 2);
|
|
$.stop = readUb($bytes, $stream, 1);
|
|
$.noMultiple = readUb($bytes, $stream, 1);
|
|
var hasEnvelope = $.hasEnvelope = readUb($bytes, $stream, 1);
|
|
var hasLoops = $.hasLoops = readUb($bytes, $stream, 1);
|
|
var hasOutPoint = $.hasOutPoint = readUb($bytes, $stream, 1);
|
|
var hasInPoint = $.hasInPoint = readUb($bytes, $stream, 1);
|
|
if (hasInPoint) {
|
|
$.inPoint = readUi32($bytes, $stream);
|
|
}
|
|
if (hasOutPoint) {
|
|
$.outPoint = readUi32($bytes, $stream);
|
|
}
|
|
if (hasLoops) {
|
|
$.loopCount = readUi16($bytes, $stream);
|
|
}
|
|
if (hasEnvelope) {
|
|
var envelopeCount = $.envelopeCount = readUi8($bytes, $stream);
|
|
var $1 = $.envelopes = [];
|
|
var $2 = envelopeCount;
|
|
while ($2--) {
|
|
var $3 = {};
|
|
soundEnvelope($bytes, $stream, $3, swfVersion, tagCode);
|
|
$1.push($3);
|
|
}
|
|
}
|
|
}
|
|
function button($bytes, $stream, $, swfVersion, tagCode) {
|
|
var hasFilters, blend;
|
|
var flags = readUi8($bytes, $stream);
|
|
var eob = $.eob = !flags;
|
|
if (swfVersion >= 8) {
|
|
blend = $.blend = flags >> 5 & 1;
|
|
hasFilters = $.hasFilters = flags >> 4 & 1;
|
|
} else {
|
|
blend = $.blend = 0;
|
|
hasFilters = $.hasFilters = 0;
|
|
}
|
|
$.stateHitTest = flags >> 3 & 1;
|
|
$.stateDown = flags >> 2 & 1;
|
|
$.stateOver = flags >> 1 & 1;
|
|
$.stateUp = flags & 1;
|
|
if (!eob) {
|
|
$.symbolId = readUi16($bytes, $stream);
|
|
$.depth = readUi16($bytes, $stream);
|
|
var $2 = $.matrix = {};
|
|
matrix($bytes, $stream, $2, swfVersion, tagCode);
|
|
if (tagCode === 34) {
|
|
var $3 = $.cxform = {};
|
|
cxform($bytes, $stream, $3, swfVersion, tagCode);
|
|
}
|
|
if (hasFilters) {
|
|
$.filterCount = readUi8($bytes, $stream);
|
|
var $4 = $.filters = {};
|
|
anyFilter($bytes, $stream, $4, swfVersion, tagCode);
|
|
}
|
|
if (blend) {
|
|
$.blendMode = readUi8($bytes, $stream);
|
|
}
|
|
}
|
|
return {
|
|
eob: eob
|
|
};
|
|
}
|
|
function buttonCondAction($bytes, $stream, $, swfVersion, tagCode) {
|
|
var buttonCondSize = readUi16($bytes, $stream);
|
|
var buttonConditions = readUi16($bytes, $stream);
|
|
$.idleToOverDown = buttonConditions >> 7 & 1;
|
|
$.outDownToIdle = buttonConditions >> 6 & 1;
|
|
$.outDownToOverDown = buttonConditions >> 5 & 1;
|
|
$.overDownToOutDown = buttonConditions >> 4 & 1;
|
|
$.overDownToOverUp = buttonConditions >> 3 & 1;
|
|
$.overUpToOverDown = buttonConditions >> 2 & 1;
|
|
$.overUpToIdle = buttonConditions >> 1 & 1;
|
|
$.idleToOverUp = buttonConditions & 1;
|
|
$.mouseEventFlags = buttonConditions & 511;
|
|
$.keyPress = buttonConditions >> 9 & 127;
|
|
$.overDownToIdle = buttonConditions >> 8 & 1;
|
|
if (!buttonCondSize) {
|
|
$.actionsData = readBinary($bytes, $stream, 0);
|
|
} else {
|
|
$.actionsData = readBinary($bytes, $stream, buttonCondSize - 4);
|
|
}
|
|
}
|
|
function shape($bytes, $stream, $, swfVersion, tagCode) {
|
|
var eos;
|
|
var temp = styleBits($bytes, $stream, $, swfVersion, tagCode);
|
|
var fillBits = temp.fillBits;
|
|
var lineBits = temp.lineBits;
|
|
var $4 = $.records = [];
|
|
do {
|
|
var $5 = {};
|
|
var isMorph = false;
|
|
var hasStrokes = false;
|
|
var temp = shapeRecord($bytes, $stream, $5, swfVersion, tagCode, isMorph, fillBits, lineBits, hasStrokes, bits);
|
|
eos = temp.eos;
|
|
var fillBits = temp.fillBits;
|
|
var lineBits = temp.lineBits;
|
|
var bits = bits;
|
|
$4.push($5);
|
|
} while (!eos);
|
|
}
|
|
return {
|
|
0: undefined,
|
|
1: undefined,
|
|
2: defineShape,
|
|
4: placeObject,
|
|
5: removeObject,
|
|
6: defineImage,
|
|
7: defineButton,
|
|
8: defineJPEGTables,
|
|
9: setBackgroundColor,
|
|
10: defineFont,
|
|
11: defineLabel,
|
|
12: doAction,
|
|
13: undefined,
|
|
14: defineSound,
|
|
15: startSound,
|
|
17: undefined,
|
|
18: soundStreamHead,
|
|
19: soundStreamBlock,
|
|
20: defineBitmap,
|
|
21: defineImage,
|
|
22: defineShape,
|
|
23: undefined,
|
|
24: undefined,
|
|
26: placeObject,
|
|
28: removeObject,
|
|
32: defineShape,
|
|
33: defineLabel,
|
|
34: defineButton,
|
|
35: defineImage,
|
|
36: defineBitmap,
|
|
37: defineText,
|
|
39: undefined,
|
|
43: frameLabel,
|
|
45: soundStreamHead,
|
|
46: defineShape,
|
|
48: defineFont2,
|
|
56: exportAssets,
|
|
57: undefined,
|
|
58: undefined,
|
|
59: doAction,
|
|
60: undefined,
|
|
61: undefined,
|
|
62: undefined,
|
|
64: undefined,
|
|
65: undefined,
|
|
66: undefined,
|
|
69: fileAttributes,
|
|
70: placeObject,
|
|
71: undefined,
|
|
72: doABC,
|
|
73: undefined,
|
|
74: undefined,
|
|
75: defineFont2,
|
|
76: symbolClass,
|
|
77: undefined,
|
|
78: defineScalingGrid,
|
|
82: doABC,
|
|
83: defineShape,
|
|
84: defineShape,
|
|
86: defineScene,
|
|
87: defineBinaryData,
|
|
88: undefined,
|
|
89: startSound,
|
|
90: defineImage,
|
|
91: undefined
|
|
};
|
|
}(this);
|
|
var readHeader = function readHeader($bytes, $stream, $, swfVersion, tagCode) {
|
|
$ || ($ = {});
|
|
var $0 = $.bbox = {};
|
|
align($bytes, $stream);
|
|
var bits = readUb($bytes, $stream, 5);
|
|
var xMin = readSb($bytes, $stream, bits);
|
|
var xMax = readSb($bytes, $stream, bits);
|
|
var yMin = readSb($bytes, $stream, bits);
|
|
var yMax = readSb($bytes, $stream, bits);
|
|
$0.xMin = xMin;
|
|
$0.xMax = xMax;
|
|
$0.yMin = yMin;
|
|
$0.yMax = yMax;
|
|
align($bytes, $stream);
|
|
var frameRateFraction = readUi8($bytes, $stream);
|
|
$.frameRate = readUi8($bytes, $stream) + frameRateFraction / 256;
|
|
$.frameCount = readUi16($bytes, $stream);
|
|
return $;
|
|
};
|
|
function readTags(context, stream, swfVersion, final, onprogress, onexception) {
|
|
var tags = context.tags;
|
|
var bytes = stream.bytes;
|
|
var lastSuccessfulPosition;
|
|
var tag = null;
|
|
if (context._readTag) {
|
|
tag = context._readTag;
|
|
context._readTag = null;
|
|
}
|
|
try {
|
|
while (stream.pos < stream.end) {
|
|
lastSuccessfulPosition = stream.pos;
|
|
stream.ensure(2);
|
|
var tagCodeAndLength = readUi16(bytes, stream);
|
|
if (!tagCodeAndLength) {
|
|
final = true;
|
|
break;
|
|
}
|
|
var tagCode = tagCodeAndLength >> 6;
|
|
var length = tagCodeAndLength & 63;
|
|
if (length === 63) {
|
|
stream.ensure(4);
|
|
length = readUi32(bytes, stream);
|
|
}
|
|
if (tag) {
|
|
if (tagCode === 1 && tag.code === 1) {
|
|
tag.repeat++;
|
|
stream.pos += length;
|
|
continue;
|
|
}
|
|
tags.push(tag);
|
|
if (onprogress && tag.id !== undefined) {
|
|
onprogress(context);
|
|
}
|
|
tag = null;
|
|
}
|
|
stream.ensure(length);
|
|
var substream = stream.substream(stream.pos, stream.pos += length);
|
|
var subbytes = substream.bytes;
|
|
var nextTag = {
|
|
code: tagCode
|
|
};
|
|
if (tagCode === 39) {
|
|
nextTag.type = 'sprite';
|
|
nextTag.id = readUi16(subbytes, substream);
|
|
nextTag.frameCount = readUi16(subbytes, substream);
|
|
nextTag.tags = [];
|
|
readTags(nextTag, substream, swfVersion, true);
|
|
} else if (tagCode === 1) {
|
|
nextTag.repeat = 1;
|
|
} else {
|
|
var handler = tagHandler[tagCode];
|
|
if (handler) {
|
|
handler(subbytes, substream, nextTag, swfVersion, tagCode);
|
|
}
|
|
}
|
|
tag = nextTag;
|
|
}
|
|
if (tag && final) {
|
|
tag.finalTag = true;
|
|
tags.push(tag);
|
|
if (onprogress) {
|
|
onprogress(context);
|
|
}
|
|
} else {
|
|
context._readTag = tag;
|
|
}
|
|
} catch (e) {
|
|
if (e !== StreamNoDataError) {
|
|
onexception && onexception(e);
|
|
throw e;
|
|
}
|
|
stream.pos = lastSuccessfulPosition;
|
|
context._readTag = tag;
|
|
}
|
|
}
|
|
function HeadTailBuffer(defaultSize) {
|
|
this.bufferSize = defaultSize || 16;
|
|
this.buffer = new Uint8Array(this.bufferSize);
|
|
this.pos = 0;
|
|
}
|
|
HeadTailBuffer.prototype = {
|
|
push: function (data, need) {
|
|
var bufferLengthNeed = this.pos + data.length;
|
|
if (this.bufferSize < bufferLengthNeed) {
|
|
var newBufferSize = this.bufferSize;
|
|
while (newBufferSize < bufferLengthNeed) {
|
|
newBufferSize <<= 1;
|
|
}
|
|
var newBuffer = new Uint8Array(newBufferSize);
|
|
if (this.bufferSize > 0) {
|
|
newBuffer.set(this.buffer);
|
|
}
|
|
this.buffer = newBuffer;
|
|
this.bufferSize = newBufferSize;
|
|
}
|
|
this.buffer.set(data, this.pos);
|
|
this.pos += data.length;
|
|
if (need)
|
|
return this.pos >= need;
|
|
},
|
|
getHead: function (size) {
|
|
return this.buffer.subarray(0, size);
|
|
},
|
|
getTail: function (offset) {
|
|
return this.buffer.subarray(offset, this.pos);
|
|
},
|
|
removeHead: function (size) {
|
|
var tail = this.getTail(size);
|
|
this.buffer = new Uint8Array(this.bufferSize);
|
|
this.buffer.set(tail);
|
|
this.pos = tail.length;
|
|
},
|
|
get arrayBuffer() {
|
|
return this.buffer.buffer;
|
|
},
|
|
get length() {
|
|
return this.pos;
|
|
},
|
|
createStream: function () {
|
|
return new Stream(this.arrayBuffer, 0, this.length);
|
|
}
|
|
};
|
|
function CompressedPipe(target, length) {
|
|
this.target = target;
|
|
this.length = length;
|
|
this.initialize = true;
|
|
this.buffer = new HeadTailBuffer(8096);
|
|
this.state = {
|
|
bitBuffer: 0,
|
|
bitLength: 0,
|
|
compression: {
|
|
header: null,
|
|
distanceTable: null,
|
|
literalTable: null,
|
|
sym: null,
|
|
len: null,
|
|
sym2: null
|
|
}
|
|
};
|
|
this.output = {
|
|
data: new Uint8Array(length),
|
|
available: 0,
|
|
completed: false
|
|
};
|
|
}
|
|
CompressedPipe.prototype = {
|
|
push: function (data, progressInfo) {
|
|
var buffer = this.buffer;
|
|
if (this.initialize) {
|
|
if (!buffer.push(data, 2))
|
|
return;
|
|
var headerBytes = buffer.getHead(2);
|
|
verifyDeflateHeader(headerBytes);
|
|
buffer.removeHead(2);
|
|
this.initialize = false;
|
|
} else {
|
|
buffer.push(data);
|
|
}
|
|
var stream = buffer.createStream();
|
|
stream.bitBuffer = this.state.bitBuffer;
|
|
stream.bitLength = this.state.bitLength;
|
|
var output = this.output;
|
|
var lastAvailable = output.available;
|
|
try {
|
|
do {
|
|
inflateBlock(stream, output, this.state.compression);
|
|
} while (stream.pos < buffer.length && !output.completed);
|
|
} catch (e) {
|
|
if (e !== InflateNoDataError)
|
|
throw e;
|
|
} finally {
|
|
this.state.bitBuffer = stream.bitBuffer;
|
|
this.state.bitLength = stream.bitLength;
|
|
}
|
|
buffer.removeHead(stream.pos);
|
|
this.target.push(output.data.subarray(lastAvailable, output.available), progressInfo);
|
|
}
|
|
};
|
|
function BodyParser(swfVersion, length, options) {
|
|
this.swf = {
|
|
swfVersion: swfVersion,
|
|
parseTime: 0
|
|
};
|
|
this.buffer = new HeadTailBuffer(32768);
|
|
this.initialize = true;
|
|
this.totalRead = 0;
|
|
this.length = length;
|
|
this.options = options;
|
|
}
|
|
BodyParser.prototype = {
|
|
push: function (data, progressInfo) {
|
|
if (data.length === 0)
|
|
return;
|
|
var swf = this.swf;
|
|
var swfVersion = swf.swfVersion;
|
|
var buffer = this.buffer;
|
|
var options = this.options;
|
|
var stream;
|
|
if (this.initialize) {
|
|
var PREFETCH_SIZE = 27;
|
|
if (!buffer.push(data, PREFETCH_SIZE))
|
|
return;
|
|
stream = buffer.createStream();
|
|
var bytes = stream.bytes;
|
|
readHeader(bytes, stream, swf);
|
|
var nextTagHeader = readUi16(bytes, stream);
|
|
var FILE_ATTRIBUTES_LENGTH = 4;
|
|
if (nextTagHeader == (SWF_TAG_CODE_FILE_ATTRIBUTES << 6 | FILE_ATTRIBUTES_LENGTH)) {
|
|
stream.ensure(FILE_ATTRIBUTES_LENGTH);
|
|
var substream = stream.substream(stream.pos, stream.pos += FILE_ATTRIBUTES_LENGTH);
|
|
var handler = tagHandler[SWF_TAG_CODE_FILE_ATTRIBUTES];
|
|
var fileAttributesTag = {
|
|
code: SWF_TAG_CODE_FILE_ATTRIBUTES
|
|
};
|
|
handler(substream.bytes, substream, fileAttributesTag, swfVersion, SWF_TAG_CODE_FILE_ATTRIBUTES);
|
|
swf.fileAttributes = fileAttributesTag;
|
|
} else {
|
|
stream.pos -= 2;
|
|
swf.fileAttributes = {};
|
|
}
|
|
if (options.onstart)
|
|
options.onstart(swf);
|
|
swf.tags = [];
|
|
this.initialize = false;
|
|
} else {
|
|
buffer.push(data);
|
|
stream = buffer.createStream();
|
|
}
|
|
var finalBlock = false;
|
|
if (progressInfo) {
|
|
swf.bytesLoaded = progressInfo.bytesLoaded;
|
|
swf.bytesTotal = progressInfo.bytesTotal;
|
|
finalBlock = progressInfo.bytesLoaded >= progressInfo.bytesTotal;
|
|
}
|
|
var readStartTime = performance.now();
|
|
readTags(swf, stream, swfVersion, finalBlock, options.onprogress, options.onexception);
|
|
swf.parseTime += performance.now() - readStartTime;
|
|
var read = stream.pos;
|
|
buffer.removeHead(read);
|
|
this.totalRead += read;
|
|
if (options.oncomplete && swf.tags[swf.tags.length - 1].finalTag) {
|
|
options.oncomplete(swf);
|
|
}
|
|
}
|
|
};
|
|
SWF.parseAsync = function swf_parseAsync(options) {
|
|
var buffer = new HeadTailBuffer();
|
|
var pipe = {
|
|
push: function (data, progressInfo) {
|
|
if (this.target !== undefined) {
|
|
return this.target.push(data, progressInfo);
|
|
}
|
|
if (!buffer.push(data, 8)) {
|
|
return null;
|
|
}
|
|
var bytes = buffer.getHead(8);
|
|
var magic1 = bytes[0];
|
|
var magic2 = bytes[1];
|
|
var magic3 = bytes[2];
|
|
if ((magic1 === 70 || magic1 === 67) && magic2 === 87 && magic3 === 83) {
|
|
var swfVersion = bytes[3];
|
|
var compressed = magic1 === 67;
|
|
parseSWF(compressed, swfVersion, progressInfo);
|
|
buffer = null;
|
|
return;
|
|
}
|
|
var isImage = false;
|
|
var imageType;
|
|
if (magic1 === 255 && magic2 === 216 && magic3 === 255) {
|
|
isImage = true;
|
|
imageType = 'image/jpeg';
|
|
} else if (magic1 === 137 && magic2 === 80 && magic3 === 78) {
|
|
isImage = true;
|
|
imageType = 'image/png';
|
|
}
|
|
if (isImage) {
|
|
parseImage(data, progressInfo.bytesTotal, imageType);
|
|
}
|
|
buffer = null;
|
|
},
|
|
close: function () {
|
|
if (buffer) {
|
|
var symbol = {
|
|
command: 'empty',
|
|
data: buffer.buffer.subarray(0, buffer.pos)
|
|
};
|
|
options.oncomplete && options.oncomplete(symbol);
|
|
}
|
|
if (this.target !== undefined && this.target.close) {
|
|
this.target.close();
|
|
}
|
|
}
|
|
};
|
|
function parseSWF(compressed, swfVersion, progressInfo) {
|
|
var stream = buffer.createStream();
|
|
stream.pos += 4;
|
|
var fileLength = readUi32(null, stream);
|
|
var bodyLength = fileLength - 8;
|
|
var target = new BodyParser(swfVersion, bodyLength, options);
|
|
if (compressed) {
|
|
target = new CompressedPipe(target, bodyLength);
|
|
}
|
|
target.push(buffer.getTail(8), progressInfo);
|
|
pipe['target'] = target;
|
|
}
|
|
function parseImage(data, bytesTotal, type) {
|
|
var buffer = new Uint8Array(bytesTotal);
|
|
buffer.set(data);
|
|
var bufferPos = data.length;
|
|
pipe['target'] = {
|
|
push: function (data) {
|
|
buffer.set(data, bufferPos);
|
|
bufferPos += data.length;
|
|
},
|
|
close: function () {
|
|
var props = {};
|
|
var chunks;
|
|
if (type == 'image/jpeg') {
|
|
chunks = parseJpegChunks(props, buffer);
|
|
} else {
|
|
chunks = [
|
|
buffer
|
|
];
|
|
}
|
|
var symbol = {
|
|
type: 'image',
|
|
props: props,
|
|
data: new Blob(chunks, {
|
|
type: type
|
|
})
|
|
};
|
|
options.oncomplete && options.oncomplete(symbol);
|
|
}
|
|
};
|
|
}
|
|
return pipe;
|
|
};
|
|
SWF.parse = function (buffer, options) {
|
|
if (!options)
|
|
options = {};
|
|
var pipe = SWF.parseAsync(options);
|
|
var bytes = new Uint8Array(buffer);
|
|
var progressInfo = {
|
|
bytesLoaded: bytes.length,
|
|
bytesTotal: bytes.length
|
|
};
|
|
pipe.push(bytes, progressInfo);
|
|
pipe.close();
|
|
};
|
|
var $RELEASE = false;
|
|
var isWorker = typeof window === 'undefined';
|
|
if (isWorker && !true) {
|
|
importScripts.apply(null, [
|
|
'../../lib/DataView.js/DataView.js',
|
|
'../flash/util.js',
|
|
'config.js',
|
|
'swf.js',
|
|
'types.js',
|
|
'structs.js',
|
|
'tags.js',
|
|
'inflate.js',
|
|
'stream.js',
|
|
'templates.js',
|
|
'generator.js',
|
|
'handlers.js',
|
|
'parser.js',
|
|
'bitmap.js',
|
|
'button.js',
|
|
'font.js',
|
|
'image.js',
|
|
'label.js',
|
|
'shape.js',
|
|
'sound.js',
|
|
'text.js'
|
|
]);
|
|
}
|
|
function defineSymbol(swfTag, symbols) {
|
|
var symbol;
|
|
switch (swfTag.code) {
|
|
case SWF_TAG_CODE_DEFINE_BITS:
|
|
case SWF_TAG_CODE_DEFINE_BITS_JPEG2:
|
|
case SWF_TAG_CODE_DEFINE_BITS_JPEG3:
|
|
case SWF_TAG_CODE_DEFINE_BITS_JPEG4:
|
|
case SWF_TAG_CODE_JPEG_TABLES:
|
|
symbol = defineImage(swfTag, symbols);
|
|
break;
|
|
case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS:
|
|
case SWF_TAG_CODE_DEFINE_BITS_LOSSLESS2:
|
|
symbol = defineBitmap(swfTag);
|
|
break;
|
|
case SWF_TAG_CODE_DEFINE_BUTTON:
|
|
case SWF_TAG_CODE_DEFINE_BUTTON2:
|
|
symbol = defineButton(swfTag, symbols);
|
|
break;
|
|
case SWF_TAG_CODE_DEFINE_EDIT_TEXT:
|
|
symbol = defineText(swfTag, symbols);
|
|
break;
|
|
case SWF_TAG_CODE_DEFINE_FONT:
|
|
case SWF_TAG_CODE_DEFINE_FONT2:
|
|
case SWF_TAG_CODE_DEFINE_FONT3:
|
|
case SWF_TAG_CODE_DEFINE_FONT4:
|
|
symbol = defineFont(swfTag, symbols);
|
|
break;
|
|
case SWF_TAG_CODE_DEFINE_MORPH_SHAPE:
|
|
case SWF_TAG_CODE_DEFINE_MORPH_SHAPE2:
|
|
case SWF_TAG_CODE_DEFINE_SHAPE:
|
|
case SWF_TAG_CODE_DEFINE_SHAPE2:
|
|
case SWF_TAG_CODE_DEFINE_SHAPE3:
|
|
case SWF_TAG_CODE_DEFINE_SHAPE4:
|
|
symbol = defineShape(swfTag, symbols);
|
|
break;
|
|
case SWF_TAG_CODE_DEFINE_SOUND:
|
|
symbol = defineSound(swfTag, symbols);
|
|
break;
|
|
case SWF_TAG_CODE_DEFINE_BINARY_DATA:
|
|
symbol = {
|
|
type: 'binary',
|
|
id: swfTag.id,
|
|
data: swfTag.data
|
|
};
|
|
break;
|
|
case SWF_TAG_CODE_DEFINE_SPRITE:
|
|
var depths = {};
|
|
var frame = {
|
|
type: 'frame'
|
|
};
|
|
var frames = [];
|
|
var tags = swfTag.tags;
|
|
var frameScripts = null;
|
|
var frameIndex = 0;
|
|
var soundStream = null;
|
|
for (var i = 0, n = tags.length; i < n; i++) {
|
|
var tag = tags[i];
|
|
switch (tag.code) {
|
|
case SWF_TAG_CODE_DO_ACTION:
|
|
if (!frameScripts)
|
|
frameScripts = [];
|
|
frameScripts.push(frameIndex);
|
|
frameScripts.push(tag.actionsData);
|
|
break;
|
|
case SWF_TAG_CODE_START_SOUND:
|
|
var startSounds = frame.startSounds || (frame.startSounds = []);
|
|
startSounds.push(tag);
|
|
break;
|
|
case SWF_TAG_CODE_SOUND_STREAM_HEAD:
|
|
try {
|
|
soundStream = createSoundStream(tag);
|
|
frame.soundStream = soundStream.info;
|
|
} catch (e) {
|
|
}
|
|
break;
|
|
case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
|
|
if (soundStream) {
|
|
frame.soundStreamBlock = soundStream.decode(tag.data);
|
|
}
|
|
break;
|
|
case SWF_TAG_CODE_FRAME_LABEL:
|
|
frame.labelName = tag.name;
|
|
break;
|
|
case SWF_TAG_CODE_PLACE_OBJECT:
|
|
case SWF_TAG_CODE_PLACE_OBJECT2:
|
|
case SWF_TAG_CODE_PLACE_OBJECT3:
|
|
depths[tag.depth] = tag;
|
|
break;
|
|
case SWF_TAG_CODE_REMOVE_OBJECT:
|
|
case SWF_TAG_CODE_REMOVE_OBJECT2:
|
|
depths[tag.depth] = null;
|
|
break;
|
|
case SWF_TAG_CODE_SHOW_FRAME:
|
|
frameIndex += tag.repeat;
|
|
frame.repeat = tag.repeat;
|
|
frame.depths = depths;
|
|
frames.push(frame);
|
|
depths = {};
|
|
frame = {
|
|
type: 'frame'
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
symbol = {
|
|
type: 'sprite',
|
|
id: swfTag.id,
|
|
frameCount: swfTag.frameCount,
|
|
frames: frames,
|
|
frameScripts: frameScripts
|
|
};
|
|
break;
|
|
case SWF_TAG_CODE_DEFINE_TEXT:
|
|
case SWF_TAG_CODE_DEFINE_TEXT2:
|
|
symbol = defineLabel(swfTag, symbols);
|
|
break;
|
|
}
|
|
if (!symbol) {
|
|
return {
|
|
command: 'error',
|
|
message: 'unknown symbol type: ' + swfTag.code
|
|
};
|
|
}
|
|
symbol.isSymbol = true;
|
|
symbols[swfTag.id] = symbol;
|
|
return symbol;
|
|
}
|
|
function createParsingContext(commitData) {
|
|
var depths = {};
|
|
var symbols = {};
|
|
var frame = {
|
|
type: 'frame'
|
|
};
|
|
var tagsProcessed = 0;
|
|
var soundStream = null;
|
|
var lastProgressSent = 0;
|
|
return {
|
|
onstart: function (result) {
|
|
commitData({
|
|
command: 'init',
|
|
result: result
|
|
});
|
|
},
|
|
onprogress: function (result) {
|
|
if (Date.now() - lastProgressSent > 1000 / 24 || result.bytesLoaded === result.bytesTotal) {
|
|
commitData({
|
|
command: 'progress',
|
|
result: {
|
|
bytesLoaded: result.bytesLoaded,
|
|
bytesTotal: result.bytesTotal
|
|
}
|
|
});
|
|
lastProgressSent = Date.now();
|
|
}
|
|
var tags = result.tags;
|
|
for (var n = tags.length; tagsProcessed < n; tagsProcessed++) {
|
|
var tag = tags[tagsProcessed];
|
|
if ('id' in tag) {
|
|
var symbol = defineSymbol(tag, symbols);
|
|
commitData(symbol, symbol.transferables);
|
|
continue;
|
|
}
|
|
switch (tag.code) {
|
|
case SWF_TAG_CODE_DEFINE_SCENE_AND_FRAME_LABEL_DATA:
|
|
frame.sceneData = tag;
|
|
break;
|
|
case SWF_TAG_CODE_DEFINE_SCALING_GRID:
|
|
var symbolUpdate = {
|
|
isSymbol: true,
|
|
id: tag.symbolId,
|
|
updates: {
|
|
scale9Grid: tag.splitter
|
|
}
|
|
};
|
|
commitData(symbolUpdate);
|
|
break;
|
|
case SWF_TAG_CODE_DO_ABC:
|
|
case SWF_TAG_CODE_DO_ABC_:
|
|
var abcBlocks = frame.abcBlocks;
|
|
if (abcBlocks)
|
|
abcBlocks.push({
|
|
data: tag.data,
|
|
flags: tag.flags
|
|
});
|
|
else
|
|
frame.abcBlocks = [
|
|
{
|
|
data: tag.data,
|
|
flags: tag.flags
|
|
}
|
|
];
|
|
break;
|
|
case SWF_TAG_CODE_DO_ACTION:
|
|
var actionBlocks = frame.actionBlocks;
|
|
if (actionBlocks)
|
|
actionBlocks.push(tag.actionsData);
|
|
else
|
|
frame.actionBlocks = [
|
|
tag.actionsData
|
|
];
|
|
break;
|
|
case SWF_TAG_CODE_DO_INIT_ACTION:
|
|
var initActionBlocks = frame.initActionBlocks || (frame.initActionBlocks = []);
|
|
initActionBlocks.push({
|
|
spriteId: tag.spriteId,
|
|
actionsData: tag.actionsData
|
|
});
|
|
break;
|
|
case SWF_TAG_CODE_START_SOUND:
|
|
var startSounds = frame.startSounds;
|
|
if (!startSounds)
|
|
frame.startSounds = startSounds = [];
|
|
startSounds.push(tag);
|
|
break;
|
|
case SWF_TAG_CODE_SOUND_STREAM_HEAD:
|
|
try {
|
|
soundStream = createSoundStream(tag);
|
|
frame.soundStream = soundStream.info;
|
|
} catch (e) {
|
|
}
|
|
break;
|
|
case SWF_TAG_CODE_SOUND_STREAM_BLOCK:
|
|
if (soundStream) {
|
|
frame.soundStreamBlock = soundStream.decode(tag.data);
|
|
}
|
|
break;
|
|
case SWF_TAG_CODE_EXPORT_ASSETS:
|
|
var exports = frame.exports;
|
|
if (exports)
|
|
frame.exports = exports.concat(tag.exports);
|
|
else
|
|
frame.exports = tag.exports.slice(0);
|
|
break;
|
|
case SWF_TAG_CODE_SYMBOL_CLASS:
|
|
var symbolClasses = frame.symbolClasses;
|
|
if (symbolClasses)
|
|
frame.symbolClasses = symbolClasses.concat(tag.exports);
|
|
else
|
|
frame.symbolClasses = tag.exports.slice(0);
|
|
break;
|
|
case SWF_TAG_CODE_FRAME_LABEL:
|
|
frame.labelName = tag.name;
|
|
break;
|
|
case SWF_TAG_CODE_PLACE_OBJECT:
|
|
case SWF_TAG_CODE_PLACE_OBJECT2:
|
|
case SWF_TAG_CODE_PLACE_OBJECT3:
|
|
depths[tag.depth] = tag;
|
|
break;
|
|
case SWF_TAG_CODE_REMOVE_OBJECT:
|
|
case SWF_TAG_CODE_REMOVE_OBJECT2:
|
|
depths[tag.depth] = null;
|
|
break;
|
|
case SWF_TAG_CODE_SET_BACKGROUND_COLOR:
|
|
frame.bgcolor = tag.color;
|
|
break;
|
|
case SWF_TAG_CODE_SHOW_FRAME:
|
|
frame.repeat = tag.repeat;
|
|
frame.depths = depths;
|
|
frame.complete = !(!tag.finalTag);
|
|
commitData(frame);
|
|
depths = {};
|
|
frame = {
|
|
type: 'frame'
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
oncomplete: function (result) {
|
|
commitData(result);
|
|
var stats;
|
|
if (typeof result.swfVersion === 'number') {
|
|
var bbox = result.bbox;
|
|
stats = {
|
|
topic: 'parseInfo',
|
|
parseTime: result.parseTime,
|
|
bytesTotal: result.bytesTotal,
|
|
swfVersion: result.swfVersion,
|
|
frameRate: result.frameRate,
|
|
width: (bbox.xMax - bbox.xMin) / 20,
|
|
height: (bbox.yMax - bbox.yMin) / 20,
|
|
isAvm2: !(!result.fileAttributes.doAbc)
|
|
};
|
|
}
|
|
commitData({
|
|
command: 'complete',
|
|
stats: stats
|
|
});
|
|
},
|
|
onexception: function (e) {
|
|
commitData({
|
|
type: 'exception',
|
|
message: e.message,
|
|
stack: e.stack
|
|
});
|
|
}
|
|
};
|
|
}
|
|
function parseBytes(bytes, commitData) {
|
|
SWF.parse(bytes, createParsingContext(commitData));
|
|
}
|
|
function ResourceLoader(scope) {
|
|
this.subscription = null;
|
|
var self = this;
|
|
if (!isWorker) {
|
|
this.messenger = {
|
|
postMessage: function (data) {
|
|
self.onmessage({
|
|
data: data
|
|
});
|
|
}
|
|
};
|
|
} else {
|
|
this.messenger = scope;
|
|
scope.onmessage = function (event) {
|
|
self.listener(event.data);
|
|
};
|
|
}
|
|
}
|
|
ResourceLoader.prototype = {
|
|
terminate: function () {
|
|
this.messenger = null;
|
|
this.listener = null;
|
|
},
|
|
onmessage: function (event) {
|
|
this.listener(event.data);
|
|
},
|
|
postMessage: function (data) {
|
|
this.listener && this.listener(data);
|
|
},
|
|
listener: function (data) {
|
|
if (this.subscription) {
|
|
this.subscription.callback(data.data, data.progress);
|
|
} else if (data === 'pipe:') {
|
|
this.subscription = {
|
|
subscribe: function (callback) {
|
|
this.callback = callback;
|
|
}
|
|
};
|
|
this.parseLoadedData(this.messenger, this.subscription);
|
|
} else {
|
|
this.parseLoadedData(this.messenger, data);
|
|
}
|
|
},
|
|
parseLoadedData: function (loader, request, context) {
|
|
function commitData(data, transferables) {
|
|
try {
|
|
loader.postMessage(data, transferables);
|
|
} catch (ex) {
|
|
if (ex != 'DataCloneError') {
|
|
throw ex;
|
|
}
|
|
loader.postMessage(data);
|
|
}
|
|
}
|
|
if (request instanceof ArrayBuffer) {
|
|
parseBytes(request, commitData);
|
|
} else if ('subscribe' in request) {
|
|
var pipe = SWF.parseAsync(createParsingContext(commitData));
|
|
request.subscribe(function (data, progress) {
|
|
if (data) {
|
|
pipe.push(data, progress);
|
|
} else {
|
|
pipe.close();
|
|
}
|
|
});
|
|
} else if (typeof FileReaderSync !== 'undefined') {
|
|
var reader = new FileReaderSync();
|
|
var buffer = reader.readAsArrayBuffer(request);
|
|
parseBytes(buffer, commitData);
|
|
} else {
|
|
var reader = new FileReader();
|
|
reader.onload = function () {
|
|
parseBytes(this.result, commitData);
|
|
};
|
|
reader.readAsArrayBuffer(request);
|
|
}
|
|
}
|
|
};
|
|
if (isWorker) {
|
|
var loader = new ResourceLoader(this);
|
|
}
|
|
function ActionsDataStream(array, swfVersion) {
|
|
this.array = array;
|
|
this.position = 0;
|
|
this.end = array.length;
|
|
if (swfVersion >= 6) {
|
|
this.readString = this.readUTF8String;
|
|
} else {
|
|
this.readString = this.readANSIString;
|
|
}
|
|
var buffer = new ArrayBuffer(4);
|
|
new Int32Array(buffer)[0] = 1;
|
|
if (!new Uint8Array(buffer)[0]) {
|
|
throw new Error('big-endian platform');
|
|
}
|
|
}
|
|
ActionsDataStream.prototype = {
|
|
readUI8: function ActionsDataStream_readUI8() {
|
|
return this.array[this.position++];
|
|
},
|
|
readUI16: function ActionsDataStream_readUI16() {
|
|
var position = this.position, array = this.array;
|
|
var value = array[position + 1] << 8 | array[position];
|
|
this.position = position + 2;
|
|
return value;
|
|
},
|
|
readSI16: function ActionsDataStream_readSI16() {
|
|
var position = this.position, array = this.array;
|
|
var value = array[position + 1] << 8 | array[position];
|
|
this.position = position + 2;
|
|
return value < 32768 ? value : value - 65536;
|
|
},
|
|
readInteger: function ActionsDataStream_readInteger() {
|
|
var position = this.position, array = this.array;
|
|
var value = array[position] | array[position + 1] << 8 | array[position + 2] << 16 | array[position + 3] << 24;
|
|
this.position = position + 4;
|
|
return value;
|
|
},
|
|
readFloat: function ActionsDataStream_readFloat() {
|
|
var position = this.position;
|
|
var array = this.array;
|
|
var buffer = new ArrayBuffer(4);
|
|
var bytes = new Uint8Array(buffer);
|
|
bytes[0] = array[position];
|
|
bytes[1] = array[position + 1];
|
|
bytes[2] = array[position + 2];
|
|
bytes[3] = array[position + 3];
|
|
this.position = position + 4;
|
|
return new Float32Array(buffer)[0];
|
|
},
|
|
readDouble: function ActionsDataStream_readDouble() {
|
|
var position = this.position;
|
|
var array = this.array;
|
|
var buffer = new ArrayBuffer(8);
|
|
var bytes = new Uint8Array(buffer);
|
|
bytes[4] = array[position];
|
|
bytes[5] = array[position + 1];
|
|
bytes[6] = array[position + 2];
|
|
bytes[7] = array[position + 3];
|
|
bytes[0] = array[position + 4];
|
|
bytes[1] = array[position + 5];
|
|
bytes[2] = array[position + 6];
|
|
bytes[3] = array[position + 7];
|
|
this.position = position + 8;
|
|
return new Float64Array(buffer)[0];
|
|
},
|
|
readBoolean: function ActionsDataStream_readBoolean() {
|
|
return !(!this.readUI8());
|
|
},
|
|
readANSIString: function ActionsDataStream_readANSIString() {
|
|
var value = '';
|
|
var ch;
|
|
while (ch = this.readUI8()) {
|
|
value += String.fromCharCode(ch);
|
|
}
|
|
return value;
|
|
},
|
|
readUTF8String: function ActionsDataStream_readUTF8String() {
|
|
var value = '';
|
|
var ch;
|
|
while (ch = this.readUI8()) {
|
|
if (ch < 128) {
|
|
value += String.fromCharCode(ch);
|
|
continue;
|
|
}
|
|
if ((ch & 192) === 128) {
|
|
throw new Error('Invalid UTF8 encoding');
|
|
}
|
|
var currentPrefix = 192;
|
|
var validBits = 5;
|
|
do {
|
|
var mask = currentPrefix >> 1 | 128;
|
|
if ((ch & mask) === currentPrefix) {
|
|
break;
|
|
}
|
|
currentPrefix = mask;
|
|
--validBits;
|
|
} while (validBits >= 0);
|
|
var code = ch & (1 << validBits) - 1;
|
|
for (var i = 5; i >= validBits; --i) {
|
|
ch = this.readUI8();
|
|
if ((ch & 192) !== 128) {
|
|
throw new Error('Invalid UTF8 encoding');
|
|
}
|
|
code = code << 6 | ch & 63;
|
|
}
|
|
if (code >= 65536) {
|
|
value += String.fromCharCode(code - 65536 >> 10 & 1023 | 55296, code & 1023 | 56320);
|
|
} else {
|
|
value += String.fromCharCode(code);
|
|
}
|
|
}
|
|
return value;
|
|
},
|
|
readBytes: function ActionsDataStream_readBytes(length) {
|
|
var position = this.position;
|
|
var remaining = Math.max(this.end - position, 0);
|
|
if (remaining < length) {
|
|
length = remaining;
|
|
}
|
|
var subarray = this.array.subarray(position, position + length);
|
|
this.position = position + length;
|
|
return subarray;
|
|
}
|
|
};
|
|
if (typeof GLOBAL !== 'undefined') {
|
|
GLOBAL.ActionsDataStream = ActionsDataStream;
|
|
}
|
|
var AVM1_TRACE_ENABLED = false;
|
|
var AVM1_ERRORS_IGNORED = true;
|
|
var MAX_AVM1_HANG_TIMEOUT = 1000;
|
|
var MAX_AVM1_ERRORS_LIMIT = 1000;
|
|
var MAX_AVM1_STACK_LIMIT = 256;
|
|
function AS2ScopeListItem(scope, next) {
|
|
this.scope = scope;
|
|
this.next = next;
|
|
}
|
|
AS2ScopeListItem.prototype = {
|
|
create: function (scope) {
|
|
return new AS2ScopeListItem(scope, this);
|
|
}
|
|
};
|
|
function AS2Context(swfVersion) {
|
|
this.swfVersion = swfVersion;
|
|
this.globals = new avm1lib.AS2Globals(this);
|
|
this.initialScope = new AS2ScopeListItem(this.globals, null);
|
|
this.assets = {};
|
|
this.isActive = false;
|
|
this.executionProhibited = false;
|
|
this.abortExecutionAt = 0;
|
|
this.stackDepth = 0;
|
|
this.isTryCatchListening = false;
|
|
this.errorsIgnored = 0;
|
|
this.deferScriptExecution = true;
|
|
this.pendingScripts = [];
|
|
}
|
|
AS2Context.instance = null;
|
|
AS2Context.prototype = {
|
|
addAsset: function (className, symbolProps) {
|
|
this.assets[className] = symbolProps;
|
|
},
|
|
resolveTarget: function (target) {
|
|
if (!target) {
|
|
target = this.defaultTarget;
|
|
} else if (typeof target === 'string') {
|
|
target = lookupAS2Children(target, this.defaultTarget, this.globals.asGetPublicProperty('_root'));
|
|
}
|
|
if (typeof target !== 'object' || target === null || !('$nativeObject' in target)) {
|
|
throw new Error('Invalid AS2 target object: ' + Object.prototype.toString.call(target));
|
|
}
|
|
return target;
|
|
},
|
|
resolveLevel: function (level) {
|
|
return this.resolveTarget(this.globals['_level' + level]);
|
|
},
|
|
addToPendingScripts: function (fn) {
|
|
if (!this.deferScriptExecution) {
|
|
return fn();
|
|
}
|
|
this.pendingScripts.push(fn);
|
|
},
|
|
flushPendingScripts: function () {
|
|
var scripts = this.pendingScripts;
|
|
while (scripts.length) {
|
|
scripts.shift()();
|
|
}
|
|
this.deferScriptExecution = false;
|
|
}
|
|
};
|
|
function AS2Error(error) {
|
|
this.error = error;
|
|
}
|
|
function AS2CriticalError(message, error) {
|
|
this.message = message;
|
|
this.error = error;
|
|
}
|
|
AS2CriticalError.prototype = Object.create(Error.prototype);
|
|
function isAS2MovieClip(obj) {
|
|
return typeof obj === 'object' && obj && obj instanceof avm1lib.AS2MovieClip;
|
|
}
|
|
function as2GetType(v) {
|
|
if (v === null) {
|
|
return 'null';
|
|
}
|
|
var type = typeof v;
|
|
if (type === 'function') {
|
|
return 'object';
|
|
}
|
|
if (type === 'object' && isAS2MovieClip(v)) {
|
|
return 'movieclip';
|
|
}
|
|
return type;
|
|
}
|
|
function as2ToPrimitive(value) {
|
|
return as2GetType(value) !== 'object' ? value : value.valueOf();
|
|
}
|
|
function as2ToAddPrimitive(value) {
|
|
if (as2GetType(value) !== 'object') {
|
|
return value;
|
|
}
|
|
if (value instanceof Date && AS2Context.instance.swfVersion >= 6) {
|
|
return value.toString();
|
|
} else {
|
|
return value.valueOf();
|
|
}
|
|
}
|
|
function as2ToBoolean(value) {
|
|
switch (as2GetType(value)) {
|
|
default:
|
|
case 'undefined':
|
|
case 'null':
|
|
return false;
|
|
case 'boolean':
|
|
return value;
|
|
case 'number':
|
|
return value !== 0 && !isNaN(value);
|
|
case 'string':
|
|
return value.length !== 0;
|
|
case 'movieclip':
|
|
case 'object':
|
|
return true;
|
|
}
|
|
}
|
|
function as2ToNumber(value) {
|
|
value = as2ToPrimitive(value);
|
|
switch (as2GetType(value)) {
|
|
case 'undefined':
|
|
case 'null':
|
|
return AS2Context.instance.swfVersion >= 7 ? NaN : 0;
|
|
case 'boolean':
|
|
return value ? 1 : +0;
|
|
case 'number':
|
|
return value;
|
|
case 'string':
|
|
if (value === '' && AS2Context.instance.swfVersion < 5) {
|
|
return 0;
|
|
}
|
|
return +value;
|
|
default:
|
|
return AS2Context.instance.swfVersion >= 5 ? NaN : 0;
|
|
}
|
|
}
|
|
function as2ToInteger(value) {
|
|
var result = as2ToNumber(value);
|
|
if (isNaN(result)) {
|
|
return 0;
|
|
}
|
|
if (!isFinite(result) || result === 0) {
|
|
return result;
|
|
}
|
|
return (result < 0 ? -1 : 1) * Math.abs(result) | 0;
|
|
}
|
|
function as2ToInt32(value) {
|
|
var result = as2ToNumber(value);
|
|
return isNaN(result) || !isFinite(result) || result === 0 ? 0 : result | 0;
|
|
}
|
|
function as2ToString(value) {
|
|
switch (as2GetType(value)) {
|
|
case 'undefined':
|
|
return AS2Context.instance.swfVersion >= 7 ? 'undefined' : '';
|
|
case 'null':
|
|
return 'null';
|
|
case 'boolean':
|
|
return value ? 'true' : 'false';
|
|
case 'number':
|
|
return value.toString();
|
|
case 'string':
|
|
return value;
|
|
case 'movieclip':
|
|
return value.$targetPath;
|
|
case 'object':
|
|
var result = value.toString !== Function.prototype.toString ? value.toString() : value;
|
|
if (typeof result === 'string') {
|
|
return result;
|
|
}
|
|
return typeof value === 'function' ? '[type Function]' : '[type Object]';
|
|
}
|
|
}
|
|
function as2Compare(x, y) {
|
|
var x2 = as2ToPrimitive(x);
|
|
var y2 = as2ToPrimitive(y);
|
|
if (typeof x2 === 'string' && typeof y2 === 'string') {
|
|
return x2 < y2;
|
|
} else {
|
|
return as2ToNumber(x2) < as2ToNumber(y2);
|
|
}
|
|
}
|
|
function as2InstanceOf(obj, constructor) {
|
|
if (obj instanceof constructor) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function as2ResolveProperty(obj, name) {
|
|
var avm2PublicName = Multiname.getPublicQualifiedName(name);
|
|
if (avm2PublicName in obj) {
|
|
return name;
|
|
}
|
|
if (isNumeric(name)) {
|
|
return null;
|
|
}
|
|
var lowerCaseName = avm2PublicName.toLowerCase();
|
|
for (var i in obj) {
|
|
if (i.toLowerCase() === lowerCaseName) {
|
|
notImplemented('FIX THIS');
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
function as2GetPrototype(obj) {
|
|
return obj && obj.asGetPublicProperty('prototype');
|
|
}
|
|
function isAvm2Class(obj) {
|
|
return typeof obj === 'object' && obj !== null && 'instanceConstructor' in obj;
|
|
}
|
|
function as2CreatePrototypeProxy(obj) {
|
|
var prototype = obj.asGetPublicProperty('prototype');
|
|
if (typeof Proxy === 'undefined') {
|
|
console.error('ES6 proxies are not found');
|
|
return prototype;
|
|
}
|
|
return Proxy.create({
|
|
getOwnPropertyDescriptor: function (name) {
|
|
return Object.getOwnPropertyDescriptor(prototype, name);
|
|
},
|
|
getPropertyDescriptor: function (name) {
|
|
for (var p = prototype; p; p = Object.getPrototypeOf(p)) {
|
|
var desc = Object.getOwnPropertyDescriptor(p, name);
|
|
if (desc)
|
|
return desc;
|
|
}
|
|
},
|
|
getOwnPropertyNames: function () {
|
|
return Object.getOwnPropertyNames(prototype);
|
|
},
|
|
getPropertyNames: function () {
|
|
var names = Object.getOwnPropertyNames(prototype);
|
|
for (var p = Object.getPrototypeOf(prototype); p; p = Object.getPrototypeOf(p)) {
|
|
names = names.concat(Object.getOwnPropertyNames(p));
|
|
}
|
|
return names;
|
|
},
|
|
defineProperty: function (name, desc) {
|
|
if (desc) {
|
|
if (typeof desc.value === 'function' && desc.value._setClass) {
|
|
desc.value._setClass(obj);
|
|
}
|
|
if (typeof desc.get === 'function' && desc.get._setClass) {
|
|
desc.get._setClass(obj);
|
|
}
|
|
if (typeof desc.set === 'function' && desc.set._setClass) {
|
|
desc.set._setClass(obj);
|
|
}
|
|
}
|
|
return Object.defineProperty(prototype, name, desc);
|
|
},
|
|
delete: function (name) {
|
|
return delete prototype[name];
|
|
},
|
|
fix: function () {
|
|
return undefined;
|
|
}
|
|
});
|
|
}
|
|
function executeActions(actionsData, context, scope) {
|
|
if (context.executionProhibited) {
|
|
return;
|
|
}
|
|
var actionTracer = ActionTracerFactory.get();
|
|
var scopeContainer = context.initialScope.create(scope);
|
|
var savedContext = AS2Context.instance;
|
|
try {
|
|
AS2Context.instance = context;
|
|
context.isActive = true;
|
|
context.abortExecutionAt = Date.now() + MAX_AVM1_HANG_TIMEOUT;
|
|
context.errorsIgnored = 0;
|
|
context.defaultTarget = scope;
|
|
context.globals.asSetPublicProperty('this', scope);
|
|
actionTracer.message('ActionScript Execution Starts');
|
|
actionTracer.indent();
|
|
interpretActions(actionsData, scopeContainer, null, []);
|
|
} catch (e) {
|
|
if (e instanceof AS2CriticalError) {
|
|
console.error('Disabling AVM1 execution');
|
|
context.executionProhibited = true;
|
|
}
|
|
throw e;
|
|
} finally {
|
|
context.isActive = false;
|
|
actionTracer.unindent();
|
|
actionTracer.message('ActionScript Execution Stops');
|
|
AS2Context.instance = savedContext;
|
|
}
|
|
}
|
|
function lookupAS2Children(targetPath, defaultTarget, root) {
|
|
var path = targetPath.split(/[\/.]/g);
|
|
if (path[path.length - 1] === '') {
|
|
path.pop();
|
|
}
|
|
var obj = defaultTarget;
|
|
if (path[0] === '' || path[0] === '_level0' || path[0] === '_root') {
|
|
obj = root;
|
|
path.shift();
|
|
}
|
|
while (path.length > 0) {
|
|
var prevObj = obj;
|
|
obj = obj.$lookupChild(path[0]);
|
|
if (!obj) {
|
|
throw new Error(path[0] + ' (expr ' + targetPath + ') is not found in ' + prevObj._target);
|
|
}
|
|
path.shift();
|
|
}
|
|
return obj;
|
|
}
|
|
function createBuiltinType(obj, args) {
|
|
if (obj === Array) {
|
|
var result = args;
|
|
if (args.length == 1 && typeof args[0] === 'number') {
|
|
result = [];
|
|
result.length = args[0];
|
|
}
|
|
return result;
|
|
}
|
|
if (obj === Boolean || obj === Number || obj === String || obj === Function) {
|
|
return obj.apply(null, args);
|
|
}
|
|
if (obj === Date) {
|
|
switch (args.length) {
|
|
case 0:
|
|
return new Date();
|
|
case 1:
|
|
return new Date(args[0]);
|
|
default:
|
|
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);
|
|
}
|
|
}
|
|
if (obj === Object) {
|
|
return {};
|
|
}
|
|
}
|
|
var AS2_SUPER_STUB = {};
|
|
function interpretActions(actionsData, scopeContainer, constantPool, registers) {
|
|
var currentContext = AS2Context.instance;
|
|
function setTarget(targetPath) {
|
|
if (!targetPath) {
|
|
currentContext.defaultTarget = scope;
|
|
return;
|
|
}
|
|
try {
|
|
currentContext.defaultTarget = lookupAS2Children(targetPath, defaultTarget, _global.asGetPublicProperty('_root'));
|
|
} catch (e) {
|
|
currentContext.defaultTarget = null;
|
|
throw e;
|
|
}
|
|
}
|
|
function defineFunction(functionName, parametersNames, registersAllocation, actionsData) {
|
|
var ownerClass;
|
|
var fn = function () {
|
|
var newScope = {};
|
|
newScope.asSetPublicProperty('this', this);
|
|
newScope.asSetPublicProperty('arguments', arguments);
|
|
newScope.asSetPublicProperty('super', AS2_SUPER_STUB);
|
|
newScope.asSetPublicProperty('__class', ownerClass);
|
|
var newScopeContainer = scopeContainer.create(newScope);
|
|
var i;
|
|
for (i = 0; i < arguments.length || i < parametersNames.length; i++) {
|
|
newScope.asSetPublicProperty(parametersNames[i], arguments[i]);
|
|
}
|
|
var registers = [];
|
|
if (registersAllocation) {
|
|
for (i = 0; i < registersAllocation.length; i++) {
|
|
var registerAllocation = registersAllocation[i];
|
|
if (!registerAllocation) {
|
|
continue;
|
|
}
|
|
if (registerAllocation.type == 'param') {
|
|
registers[i] = arguments[registerAllocation.index];
|
|
} else {
|
|
switch (registerAllocation.name) {
|
|
case 'this':
|
|
registers[i] = this;
|
|
break;
|
|
case 'arguments':
|
|
registers[i] = arguments;
|
|
break;
|
|
case 'super':
|
|
registers[i] = AS2_SUPER_STUB;
|
|
break;
|
|
case '_global':
|
|
registers[i] = _global;
|
|
break;
|
|
case '_parent':
|
|
registers[i] = scope.asGetPublicProperty('_parent');
|
|
break;
|
|
case '_root':
|
|
registers[i] = _global.asGetPublicProperty('_root');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var savedContext = AS2Context.instance;
|
|
var savedIsActive = currentContext.isActive;
|
|
try {
|
|
AS2Context.instance = currentContext;
|
|
if (!savedIsActive) {
|
|
currentContext.abortExecutionAt = Date.now() + MAX_AVM1_HANG_TIMEOUT;
|
|
currentContext.errorsIgnored = 0;
|
|
currentContext.isActive = true;
|
|
}
|
|
currentContext.defaultTarget = scope;
|
|
actionTracer.indent();
|
|
currentContext.stackDepth++;
|
|
if (currentContext.stackDepth >= MAX_AVM1_STACK_LIMIT) {
|
|
throw new AS2CriticalError('long running script -- AVM1 recursion limit is reached');
|
|
}
|
|
return interpretActions(actionsData, newScopeContainer, constantPool, registers);
|
|
} finally {
|
|
currentContext.isActive = savedIsActive;
|
|
currentContext.stackDepth--;
|
|
actionTracer.unindent();
|
|
currentContext.defaultTarget = defaultTarget;
|
|
AS2Context.instance = savedContext;
|
|
}
|
|
};
|
|
ownerClass = fn;
|
|
fn._setClass = function (class_) {
|
|
ownerClass = class_;
|
|
};
|
|
fn.instanceConstructor = fn;
|
|
fn.debugName = 'avm1 ' + (functionName || '<function>');
|
|
if (functionName) {
|
|
fn.name = functionName;
|
|
}
|
|
return fn;
|
|
}
|
|
function deleteProperty(propertyName) {
|
|
for (var p = scopeContainer; p; p = p.next) {
|
|
if (p.scope.asHasProperty(undefined, propertyName, 0)) {
|
|
p.scope.asSetPublicProperty(propertyName, undefined);
|
|
return p.scope.asDeleteProperty(undefined, propertyName, 0);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function resolveVariableName(variableName, nonStrict) {
|
|
var obj, name, i;
|
|
if (variableName.indexOf(':') >= 0) {
|
|
var parts = variableName.split(':');
|
|
obj = lookupAS2Children(parts[0], defaultTarget, _global.asGetPublicProperty('_root'));
|
|
if (!obj) {
|
|
throw new Error(parts[0] + ' is undefined');
|
|
}
|
|
name = parts[1];
|
|
} else if (variableName.indexOf('.') >= 0) {
|
|
var objPath = variableName.split('.');
|
|
name = objPath.pop();
|
|
obj = _global;
|
|
for (i = 0; i < objPath.length; i++) {
|
|
obj = obj.asGetPublicProperty(objPath[i]) || obj[objPath[i]];
|
|
if (!obj) {
|
|
throw new Error(objPath.slice(0, i + 1) + ' is undefined');
|
|
}
|
|
}
|
|
}
|
|
if (!obj) {
|
|
return null;
|
|
}
|
|
var resolvedName = as2ResolveProperty(obj, name);
|
|
var resolved = resolvedName !== null;
|
|
if (resolved || nonStrict) {
|
|
return {
|
|
obj: obj,
|
|
name: resolvedName || name,
|
|
resolved: resolved
|
|
};
|
|
}
|
|
return null;
|
|
}
|
|
function getThis() {
|
|
var _this = scope.asGetPublicProperty('this');
|
|
if (_this) {
|
|
return _this;
|
|
}
|
|
for (var p = scopeContainer; p; p = p.next) {
|
|
resolvedName = as2ResolveProperty(p.scope, 'this');
|
|
if (resolvedName !== null) {
|
|
return p.scope.asGetPublicProperty(resolvedName);
|
|
}
|
|
}
|
|
}
|
|
function getVariable(variableName) {
|
|
if (scope.asHasProperty(undefined, variableName, 0)) {
|
|
return scope.asGetPublicProperty(variableName);
|
|
}
|
|
var target = resolveVariableName(variableName);
|
|
if (target) {
|
|
return target.obj.asGetPublicProperty(target.name);
|
|
}
|
|
var resolvedName, _this = getThis();
|
|
for (var p = scopeContainer; p; p = p.next) {
|
|
resolvedName = as2ResolveProperty(p.scope, variableName);
|
|
if (resolvedName !== null) {
|
|
return p.scope.asGetPublicProperty(resolvedName);
|
|
}
|
|
}
|
|
if (_this && (resolvedName = as2ResolveProperty(_this, variableName))) {
|
|
return _this.asGetPublicProperty(resolvedName);
|
|
}
|
|
var mc = isAS2MovieClip(defaultTarget) && defaultTarget.$lookupChild(variableName);
|
|
if (mc) {
|
|
return mc;
|
|
}
|
|
}
|
|
function setVariable(variableName, value) {
|
|
if (scope.asHasProperty(undefined, variableName, 0)) {
|
|
scope.asSetPublicProperty(variableName, value);
|
|
return;
|
|
}
|
|
var target = resolveVariableName(variableName, true);
|
|
if (target) {
|
|
target.obj.asSetPublicProperty(target.name, value);
|
|
return;
|
|
}
|
|
var resolvedName, _this = getThis();
|
|
if (_this && (resolvedName = as2ResolveProperty(_this, variableName))) {
|
|
return _this.asSetPublicProperty(resolvedName, value);
|
|
}
|
|
for (var p = scopeContainer; p.next; p = p.next) {
|
|
resolvedName = as2ResolveProperty(p.scope, variableName);
|
|
if (resolvedName !== null) {
|
|
return p.scope.asSetPublicProperty(resolvedName, value);
|
|
}
|
|
}
|
|
(_this || scope).asSetPublicProperty(variableName, value);
|
|
}
|
|
function getFunction(functionName) {
|
|
var fn = getVariable(functionName);
|
|
if (!(fn instanceof Function)) {
|
|
throw new Error('Function "' + functionName + '" is not found');
|
|
}
|
|
return fn;
|
|
}
|
|
function getObjectByName(objectName) {
|
|
var obj = getVariable(objectName);
|
|
if (!(obj instanceof Object)) {
|
|
throw new Error('Object "' + objectName + '" is not found');
|
|
}
|
|
return obj;
|
|
}
|
|
function processWith(obj, withBlock) {
|
|
var newScopeContainer = scopeContainer.create(Object(obj));
|
|
interpretActions(withBlock, newScopeContainer, constantPool, registers);
|
|
}
|
|
function processTry(catchIsRegisterFlag, finallyBlockFlag, catchBlockFlag, catchTarget, tryBlock, catchBlock, finallyBlock) {
|
|
var savedTryCatchState = currentContext.isTryCatchListening;
|
|
try {
|
|
currentContext.isTryCatchListening = true;
|
|
interpretActions(tryBlock, scopeContainer, constantPool, registers);
|
|
} catch (e) {
|
|
currentContext.isTryCatchListening = savedTryCatchState;
|
|
if (!catchBlockFlag) {
|
|
throw e;
|
|
}
|
|
if (!(e instanceof AS2Error)) {
|
|
throw e;
|
|
}
|
|
if (typeof catchTarget === 'string') {
|
|
scope[catchTarget] = e.error;
|
|
} else {
|
|
registers[catchTarget] = e.error;
|
|
}
|
|
interpretActions(catchBlock, scopeContainer, constantPool, registers);
|
|
} finally {
|
|
currentContext.isTryCatchListening = savedTryCatchState;
|
|
if (finallyBlockFlag) {
|
|
interpretActions(finallyBlock, scopeContainer, constantPool, registers);
|
|
}
|
|
}
|
|
}
|
|
function validateArgsCount(numArgs, maxAmount) {
|
|
if (isNaN(numArgs) || numArgs < 0 || numArgs > maxAmount || numArgs != (0 | numArgs)) {
|
|
throw new Error('Invalid number of arguments: ' + numArgs);
|
|
}
|
|
}
|
|
function readArgs(stack) {
|
|
var numArgs = +stack.pop();
|
|
validateArgsCount(numArgs, stack.length);
|
|
var args = [];
|
|
for (var i = 0; i < numArgs; i++) {
|
|
args.push(stack.pop());
|
|
}
|
|
return args;
|
|
}
|
|
var stream = new ActionsDataStream(actionsData, currentContext.swfVersion);
|
|
var _global = currentContext.globals;
|
|
var defaultTarget = currentContext.defaultTarget;
|
|
var stack = [];
|
|
var scope = scopeContainer.scope;
|
|
var isSwfVersion5 = currentContext.swfVersion >= 5;
|
|
var actionTracer = ActionTracerFactory.get();
|
|
var nextPosition;
|
|
if (scope.$nativeObject && scope.$nativeObject._deferScriptExecution) {
|
|
currentContext.deferScriptExecution = true;
|
|
}
|
|
function skipActions(count) {
|
|
while (count > 0 && stream.position < stream.end) {
|
|
var actionCode = stream.readUI8();
|
|
var length = actionCode >= 128 ? stream.readUI16() : 0;
|
|
stream.position += length;
|
|
count--;
|
|
}
|
|
nextPosition = stream.position;
|
|
}
|
|
var recoveringFromError = false;
|
|
var stackItemsExpected;
|
|
while (stream.position < stream.end) {
|
|
try {
|
|
var instructionsExecuted = 0;
|
|
var abortExecutionAt = currentContext.abortExecutionAt;
|
|
while (stream.position < stream.end) {
|
|
if (instructionsExecuted++ % 100 === 0 && Date.now() >= abortExecutionAt) {
|
|
throw new AS2CriticalError('long running script -- AVM1 instruction hang timeout');
|
|
}
|
|
var actionCode = stream.readUI8();
|
|
var length = actionCode >= 128 ? stream.readUI16() : 0;
|
|
nextPosition = stream.position + length;
|
|
stackItemsExpected = 0;
|
|
actionTracer.print(stream.position, actionCode, stack);
|
|
var frame, type, count, index, target, method, constr, codeSize, offset;
|
|
var name, variableName, methodName, functionName, targetName;
|
|
var paramName, resolvedName, objectName;
|
|
var value, a, b, c, f, sa, sb, obj, args, fn, result, flags, i;
|
|
var dragParams, register;
|
|
switch (actionCode | 0) {
|
|
case 129:
|
|
frame = stream.readUI16();
|
|
var nextActionCode = stream.readUI8();
|
|
nextPosition++;
|
|
methodName = nextActionCode === 6 ? 'gotoAndPlay' : 'gotoAndStop';
|
|
_global[methodName](frame + 1);
|
|
break;
|
|
case 131:
|
|
var urlString = stream.readString();
|
|
var targetString = stream.readString();
|
|
_global.getURL(urlString, targetString);
|
|
break;
|
|
case 4:
|
|
_global.nextFrame();
|
|
break;
|
|
case 5:
|
|
_global.prevFrame();
|
|
break;
|
|
case 6:
|
|
_global.play();
|
|
break;
|
|
case 7:
|
|
_global.stop();
|
|
break;
|
|
case 8:
|
|
_global.toggleHighQuality();
|
|
break;
|
|
case 9:
|
|
_global.stopAllSounds();
|
|
break;
|
|
case 138:
|
|
frame = stream.readUI16();
|
|
count = stream.readUI8();
|
|
if (!_global.ifFrameLoaded(frame)) {
|
|
skipActions(count);
|
|
}
|
|
break;
|
|
case 139:
|
|
targetName = stream.readString();
|
|
setTarget(targetName);
|
|
break;
|
|
case 140:
|
|
var label = stream.readString();
|
|
_global.gotoLabel(label);
|
|
break;
|
|
case 150:
|
|
while (stream.position < nextPosition) {
|
|
type = stream.readUI8();
|
|
switch (type) {
|
|
case 0:
|
|
value = stream.readString();
|
|
break;
|
|
case 1:
|
|
value = stream.readFloat();
|
|
break;
|
|
case 2:
|
|
value = null;
|
|
break;
|
|
case 3:
|
|
value = void 0;
|
|
break;
|
|
case 4:
|
|
value = registers[stream.readUI8()];
|
|
break;
|
|
case 5:
|
|
value = stream.readBoolean();
|
|
break;
|
|
case 6:
|
|
value = stream.readDouble();
|
|
break;
|
|
case 7:
|
|
value = stream.readInteger();
|
|
break;
|
|
case 8:
|
|
value = constantPool[stream.readUI8()];
|
|
break;
|
|
case 9:
|
|
value = constantPool[stream.readUI16()];
|
|
break;
|
|
default:
|
|
throw new Error('Unknown value type: ' + type);
|
|
}
|
|
stack.push(value);
|
|
}
|
|
break;
|
|
case 23:
|
|
stack.pop();
|
|
break;
|
|
case 10:
|
|
a = as2ToNumber(stack.pop());
|
|
b = as2ToNumber(stack.pop());
|
|
stack.push(a + b);
|
|
break;
|
|
case 11:
|
|
a = as2ToNumber(stack.pop());
|
|
b = as2ToNumber(stack.pop());
|
|
stack.push(b - a);
|
|
break;
|
|
case 12:
|
|
a = as2ToNumber(stack.pop());
|
|
b = as2ToNumber(stack.pop());
|
|
stack.push(a * b);
|
|
break;
|
|
case 13:
|
|
a = as2ToNumber(stack.pop());
|
|
b = as2ToNumber(stack.pop());
|
|
c = b / a;
|
|
stack.push(isSwfVersion5 ? c : isFinite(c) ? c : '#ERROR#');
|
|
break;
|
|
case 14:
|
|
a = as2ToNumber(stack.pop());
|
|
b = as2ToNumber(stack.pop());
|
|
f = a == b;
|
|
stack.push(isSwfVersion5 ? f : f ? 1 : 0);
|
|
break;
|
|
case 15:
|
|
a = as2ToNumber(stack.pop());
|
|
b = as2ToNumber(stack.pop());
|
|
f = b < a;
|
|
stack.push(isSwfVersion5 ? f : f ? 1 : 0);
|
|
break;
|
|
case 16:
|
|
a = as2ToBoolean(stack.pop());
|
|
b = as2ToBoolean(stack.pop());
|
|
f = a && b;
|
|
stack.push(isSwfVersion5 ? f : f ? 1 : 0);
|
|
break;
|
|
case 17:
|
|
a = as2ToBoolean(stack.pop());
|
|
b = as2ToBoolean(stack.pop());
|
|
f = a || b;
|
|
stack.push(isSwfVersion5 ? f : f ? 1 : 0);
|
|
break;
|
|
case 18:
|
|
f = !as2ToBoolean(stack.pop());
|
|
stack.push(isSwfVersion5 ? f : f ? 1 : 0);
|
|
break;
|
|
case 19:
|
|
sa = as2ToString(stack.pop());
|
|
sb = as2ToString(stack.pop());
|
|
f = sa == sb;
|
|
stack.push(isSwfVersion5 ? f : f ? 1 : 0);
|
|
break;
|
|
case 20:
|
|
case 49:
|
|
sa = as2ToString(stack.pop());
|
|
stack.push(_global.length(sa));
|
|
break;
|
|
case 33:
|
|
sa = as2ToString(stack.pop());
|
|
sb = as2ToString(stack.pop());
|
|
stack.push(sb + sa);
|
|
break;
|
|
case 21:
|
|
count = stack.pop();
|
|
index = stack.pop();
|
|
value = as2ToString(stack.pop());
|
|
stack.push(_global.substring(value, index, count));
|
|
break;
|
|
case 53:
|
|
count = stack.pop();
|
|
index = stack.pop();
|
|
value = as2ToString(stack.pop());
|
|
stack.push(_global.mbsubstring(value, index, count));
|
|
break;
|
|
case 41:
|
|
sa = as2ToString(stack.pop());
|
|
sb = as2ToString(stack.pop());
|
|
f = sb < sa;
|
|
stack.push(isSwfVersion5 ? f : f ? 1 : 0);
|
|
break;
|
|
case 24:
|
|
stack.push(_global.int(stack.pop()));
|
|
break;
|
|
case 50:
|
|
stack.push(_global.chr(stack.pop()));
|
|
break;
|
|
case 54:
|
|
stack.push(_global.mbchr(stack.pop()));
|
|
break;
|
|
case 51:
|
|
stack.push(_global.ord(stack.pop()));
|
|
break;
|
|
case 55:
|
|
stack.push(_global.mbord(stack.pop()));
|
|
break;
|
|
case 153:
|
|
offset = stream.readSI16();
|
|
nextPosition += offset;
|
|
break;
|
|
case 157:
|
|
offset = stream.readSI16();
|
|
f = !(!stack.pop());
|
|
if (f) {
|
|
nextPosition += offset;
|
|
}
|
|
break;
|
|
case 158:
|
|
label = stack.pop();
|
|
_global.call(label);
|
|
break;
|
|
case 28:
|
|
variableName = '' + stack.pop();
|
|
stackItemsExpected++;
|
|
stack.push(getVariable(variableName));
|
|
break;
|
|
case 29:
|
|
value = stack.pop();
|
|
variableName = '' + stack.pop();
|
|
setVariable(variableName, value);
|
|
break;
|
|
case 154:
|
|
flags = stream.readUI8();
|
|
target = stack.pop();
|
|
var url = stack.pop();
|
|
var sendVarsMethod;
|
|
if (flags & 1) {
|
|
sendVarsMethod = 'GET';
|
|
} else if (flags & 2) {
|
|
sendVarsMethod = 'POST';
|
|
}
|
|
var loadTargetFlag = flags & 1 << 6;
|
|
if (!loadTargetFlag) {
|
|
_global.getURL(url, target, sendVarsMethod);
|
|
break;
|
|
}
|
|
var loadVariablesFlag = flags & 1 << 7;
|
|
if (loadVariablesFlag) {
|
|
_global.loadVariables(url, target, sendVarsMethod);
|
|
} else {
|
|
_global.loadMovie(url, target, sendVarsMethod);
|
|
}
|
|
break;
|
|
case 159:
|
|
flags = stream.readUI8();
|
|
var gotoParams = [
|
|
stack.pop()
|
|
];
|
|
if (!(!(flags & 2))) {
|
|
gotoParams.push(stream.readUI16());
|
|
}
|
|
var gotoMethod = !(!(flags & 1)) ? _global.gotoAndPlay : _global.gotoAndStop;
|
|
gotoMethod.apply(_global, gotoParams);
|
|
break;
|
|
case 32:
|
|
target = stack.pop();
|
|
setTarget(target);
|
|
break;
|
|
case 34:
|
|
index = stack.pop();
|
|
target = stack.pop();
|
|
stackItemsExpected++;
|
|
stack.push(_global.getAS2Property(target, index));
|
|
break;
|
|
case 35:
|
|
value = stack.pop();
|
|
index = stack.pop();
|
|
target = stack.pop();
|
|
_global.setAS2Property(target, index, value);
|
|
break;
|
|
case 36:
|
|
var depth = stack.pop();
|
|
target = stack.pop();
|
|
var source = stack.pop();
|
|
_global.duplicateMovieClip(source, target, depth);
|
|
break;
|
|
case 37:
|
|
target = stack.pop();
|
|
_global.removeMovieClip(target);
|
|
break;
|
|
case 39:
|
|
target = stack.pop();
|
|
var lockcenter = stack.pop();
|
|
var constrain = !stack.pop() ? null : {
|
|
y2: stack.pop(),
|
|
x2: stack.pop(),
|
|
y1: stack.pop(),
|
|
x1: stack.pop()
|
|
};
|
|
dragParams = [
|
|
target,
|
|
lockcenter
|
|
];
|
|
if (constrain) {
|
|
dragParams = dragParams.push(constrain.x1, constrain.y1, constrain.x2, constrain.y2);
|
|
}
|
|
_global.startDrag.apply(_global, dragParams);
|
|
break;
|
|
case 40:
|
|
_global.stopDrag();
|
|
break;
|
|
case 141:
|
|
count = stream.readUI8();
|
|
frame = stack.pop();
|
|
if (!_global.ifFrameLoaded(frame)) {
|
|
skipActions(count);
|
|
}
|
|
break;
|
|
case 38:
|
|
value = stack.pop();
|
|
_global.trace(value);
|
|
break;
|
|
case 52:
|
|
stack.push(_global.getTimer());
|
|
break;
|
|
case 48:
|
|
stack.push(_global.random(stack.pop()));
|
|
break;
|
|
case 61:
|
|
functionName = stack.pop();
|
|
args = readArgs(stack);
|
|
stackItemsExpected++;
|
|
fn = getFunction(functionName);
|
|
result = fn.apply(scope, args);
|
|
stack.push(result);
|
|
break;
|
|
case 82:
|
|
methodName = stack.pop();
|
|
obj = stack.pop();
|
|
args = readArgs(stack);
|
|
stackItemsExpected++;
|
|
if (methodName !== null && methodName !== undefined && methodName !== '') {
|
|
if (obj === null || obj === undefined) {
|
|
throw new Error('Cannot call method ' + methodName + ' of ' + typeof obj);
|
|
} else if (obj !== AS2_SUPER_STUB) {
|
|
target = Object(obj);
|
|
} else {
|
|
target = as2GetPrototype(getVariable('__class').__super);
|
|
obj = getVariable('this');
|
|
}
|
|
resolvedName = as2ResolveProperty(target, methodName);
|
|
if (resolvedName === null) {
|
|
throw new Error('Method ' + methodName + ' is not defined.');
|
|
}
|
|
result = target.asGetPublicProperty(resolvedName).apply(obj, args);
|
|
} else if (obj !== AS2_SUPER_STUB) {
|
|
result = obj.apply(obj, args);
|
|
} else {
|
|
result = getVariable('__class').__super.apply(getVariable('this'), args);
|
|
}
|
|
stack.push(result);
|
|
break;
|
|
case 136:
|
|
count = stream.readUI16();
|
|
constantPool = [];
|
|
for (i = 0; i < count; i++) {
|
|
constantPool.push(stream.readString());
|
|
}
|
|
break;
|
|
case 155:
|
|
functionName = stream.readString();
|
|
count = stream.readUI16();
|
|
args = [];
|
|
for (i = 0; i < count; i++) {
|
|
args.push(stream.readString());
|
|
}
|
|
codeSize = stream.readUI16();
|
|
nextPosition += codeSize;
|
|
fn = defineFunction(functionName, args, null, stream.readBytes(codeSize));
|
|
if (functionName) {
|
|
scope.asSetPublicProperty(functionName, fn);
|
|
} else {
|
|
stack.push(fn);
|
|
}
|
|
break;
|
|
case 60:
|
|
value = stack.pop();
|
|
name = stack.pop();
|
|
scope.asSetPublicProperty(name, value);
|
|
break;
|
|
case 65:
|
|
name = stack.pop();
|
|
scope.asSetPublicProperty(name, undefined);
|
|
break;
|
|
case 58:
|
|
name = stack.pop();
|
|
obj = stack.pop();
|
|
obj.asSetPublicProperty(name, undefined);
|
|
stack.push(obj.asDeleteProperty(undefined, name, 0));
|
|
break;
|
|
case 59:
|
|
name = stack.pop();
|
|
result = deleteProperty(name);
|
|
stack.push(result);
|
|
break;
|
|
case 70:
|
|
objectName = stack.pop();
|
|
stack.push(null);
|
|
obj = getObjectByName(objectName);
|
|
forEachPublicProperty(obj, function (name) {
|
|
stack.push(name);
|
|
});
|
|
break;
|
|
case 73:
|
|
a = stack.pop();
|
|
b = stack.pop();
|
|
stack.push(a == b);
|
|
break;
|
|
case 78:
|
|
name = stack.pop();
|
|
obj = stack.pop();
|
|
if (name === 'prototype') {
|
|
stack.push(as2CreatePrototypeProxy(obj));
|
|
} else {
|
|
resolvedName = as2ResolveProperty(Object(obj), name);
|
|
stack.push(resolvedName === null ? undefined : obj.asGetPublicProperty(resolvedName));
|
|
}
|
|
break;
|
|
case 66:
|
|
obj = readArgs(stack);
|
|
stack.push(obj);
|
|
break;
|
|
case 67:
|
|
count = +stack.pop();
|
|
validateArgsCount(count, stack.length >> 1);
|
|
obj = {};
|
|
for (i = 0; i < count; i++) {
|
|
value = stack.pop();
|
|
name = stack.pop();
|
|
obj.asSetPublicProperty(name, value);
|
|
}
|
|
stack.push(obj);
|
|
break;
|
|
case 83:
|
|
methodName = stack.pop();
|
|
obj = stack.pop();
|
|
args = readArgs(stack);
|
|
stackItemsExpected++;
|
|
if (methodName !== null && methodName !== undefined && methodName !== '') {
|
|
resolvedName = as2ResolveProperty(obj, methodName);
|
|
if (resolvedName === null) {
|
|
throw new Error('Method ' + methodName + ' is not defined.');
|
|
}
|
|
if (obj === null || obj === undefined) {
|
|
throw new Error('Cannot call new using method ' + resolvedName + ' of ' + typeof obj);
|
|
}
|
|
method = obj.asGetPublicProperty(resolvedName);
|
|
} else {
|
|
if (obj === null || obj === undefined) {
|
|
throw new Error('Cannot call new using ' + typeof obj);
|
|
}
|
|
method = obj;
|
|
}
|
|
if (isAvm2Class(obj)) {
|
|
result = construct(obj, args);
|
|
} else {
|
|
result = Object.create(as2GetPrototype(method) || as2GetPrototype(Object));
|
|
method.apply(result, args);
|
|
}
|
|
result.constructor = method;
|
|
stack.push(result);
|
|
break;
|
|
case 64:
|
|
objectName = stack.pop();
|
|
obj = getObjectByName(objectName);
|
|
args = readArgs(stack);
|
|
stackItemsExpected++;
|
|
result = createBuiltinType(obj, args);
|
|
if (typeof result === 'undefined') {
|
|
if (isAvm2Class(obj)) {
|
|
result = construct(obj, args);
|
|
} else {
|
|
result = Object.create(as2GetPrototype(obj) || as2GetPrototype(Object));
|
|
obj.apply(result, args);
|
|
}
|
|
result.constructor = obj;
|
|
}
|
|
stack.push(result);
|
|
break;
|
|
case 79:
|
|
value = stack.pop();
|
|
name = stack.pop();
|
|
obj = stack.pop();
|
|
obj.asSetPublicProperty(name, value);
|
|
break;
|
|
case 69:
|
|
obj = stack.pop();
|
|
stack.push(as2GetType(obj) === 'movieclip' ? obj._target : void 0);
|
|
break;
|
|
case 148:
|
|
codeSize = stream.readUI16();
|
|
obj = stack.pop();
|
|
nextPosition += codeSize;
|
|
processWith(obj, stream.readBytes(codeSize));
|
|
break;
|
|
case 74:
|
|
stack.push(as2ToNumber(stack.pop()));
|
|
break;
|
|
case 75:
|
|
stack.push(as2ToString(stack.pop()));
|
|
break;
|
|
case 68:
|
|
obj = stack.pop();
|
|
result = as2GetType(obj);
|
|
stack.push(result);
|
|
break;
|
|
case 71:
|
|
a = as2ToAddPrimitive(stack.pop());
|
|
b = as2ToAddPrimitive(stack.pop());
|
|
if (typeof a === 'string' || typeof b === 'string') {
|
|
stack.push(as2ToString(b) + as2ToString(a));
|
|
} else {
|
|
stack.push(as2ToNumber(b) + as2ToNumber(a));
|
|
}
|
|
break;
|
|
case 72:
|
|
a = stack.pop();
|
|
b = stack.pop();
|
|
stack.push(as2Compare(b, a));
|
|
break;
|
|
case 63:
|
|
a = as2ToNumber(stack.pop());
|
|
b = as2ToNumber(stack.pop());
|
|
stack.push(b % a);
|
|
break;
|
|
case 96:
|
|
a = as2ToInt32(stack.pop());
|
|
b = as2ToInt32(stack.pop());
|
|
stack.push(b & a);
|
|
break;
|
|
case 99:
|
|
a = as2ToInt32(stack.pop());
|
|
b = as2ToInt32(stack.pop());
|
|
stack.push(b << a);
|
|
break;
|
|
case 97:
|
|
a = as2ToInt32(stack.pop());
|
|
b = as2ToInt32(stack.pop());
|
|
stack.push(b | a);
|
|
break;
|
|
case 100:
|
|
a = as2ToInt32(stack.pop());
|
|
b = as2ToInt32(stack.pop());
|
|
stack.push(b >> a);
|
|
break;
|
|
case 101:
|
|
a = as2ToInt32(stack.pop());
|
|
b = as2ToInt32(stack.pop());
|
|
stack.push(b >>> a);
|
|
break;
|
|
case 98:
|
|
a = as2ToInt32(stack.pop());
|
|
b = as2ToInt32(stack.pop());
|
|
stack.push(b ^ a);
|
|
break;
|
|
case 81:
|
|
a = as2ToNumber(stack.pop());
|
|
a--;
|
|
stack.push(a);
|
|
break;
|
|
case 80:
|
|
a = as2ToNumber(stack.pop());
|
|
a++;
|
|
stack.push(a);
|
|
break;
|
|
case 76:
|
|
stack.push(stack[stack.length - 1]);
|
|
break;
|
|
case 62:
|
|
return stack.pop();
|
|
case 77:
|
|
stack.push(stack.pop(), stack.pop());
|
|
break;
|
|
case 135:
|
|
register = stream.readUI8();
|
|
registers[register] = stack[stack.length - 1];
|
|
break;
|
|
case 84:
|
|
constr = stack.pop();
|
|
obj = stack.pop();
|
|
stack.push(as2InstanceOf(Object(obj), constr));
|
|
break;
|
|
case 85:
|
|
obj = stack.pop();
|
|
stack.push(null);
|
|
forEachPublicProperty(obj, function (name) {
|
|
stack.push(name);
|
|
});
|
|
break;
|
|
case 102:
|
|
a = stack.pop();
|
|
b = stack.pop();
|
|
stack.push(b === a);
|
|
break;
|
|
case 103:
|
|
a = stack.pop();
|
|
b = stack.pop();
|
|
stack.push(as2Compare(a, b));
|
|
break;
|
|
case 104:
|
|
sa = as2ToString(stack.pop());
|
|
sb = as2ToString(stack.pop());
|
|
f = sb > sa;
|
|
stack.push(isSwfVersion5 ? f : f ? 1 : 0);
|
|
break;
|
|
case 142:
|
|
functionName = stream.readString();
|
|
count = stream.readUI16();
|
|
var registerCount = stream.readUI8();
|
|
flags = stream.readUI16();
|
|
var registerAllocation = [];
|
|
args = [];
|
|
for (i = 0; i < count; i++) {
|
|
register = stream.readUI8();
|
|
paramName = stream.readString();
|
|
args.push(paramName);
|
|
if (register) {
|
|
registerAllocation[register] = {
|
|
type: 'param',
|
|
name: paramName,
|
|
index: i
|
|
};
|
|
}
|
|
}
|
|
codeSize = stream.readUI16();
|
|
nextPosition += codeSize;
|
|
var j = 1;
|
|
if (flags & 1) {
|
|
registerAllocation[j++] = {
|
|
type: 'var',
|
|
name: 'this'
|
|
};
|
|
}
|
|
if (flags & 4) {
|
|
registerAllocation[j++] = {
|
|
type: 'var',
|
|
name: 'arguments'
|
|
};
|
|
}
|
|
if (flags & 16) {
|
|
registerAllocation[j++] = {
|
|
type: 'var',
|
|
name: 'super'
|
|
};
|
|
}
|
|
if (flags & 64) {
|
|
registerAllocation[j++] = {
|
|
type: 'var',
|
|
name: '_root'
|
|
};
|
|
}
|
|
if (flags & 128) {
|
|
registerAllocation[j++] = {
|
|
type: 'var',
|
|
name: '_parent'
|
|
};
|
|
}
|
|
if (flags & 256) {
|
|
registerAllocation[j++] = {
|
|
type: 'var',
|
|
name: '_global'
|
|
};
|
|
}
|
|
fn = defineFunction(functionName, args, registerAllocation, stream.readBytes(codeSize));
|
|
if (functionName) {
|
|
scope.asSetPublicProperty(functionName, fn);
|
|
} else {
|
|
stack.push(fn);
|
|
}
|
|
break;
|
|
case 105:
|
|
var constrSuper = stack.pop();
|
|
constr = stack.pop();
|
|
obj = Object.create(constrSuper.traitsPrototype || as2GetPrototype(constrSuper), {
|
|
constructor: {
|
|
value: constr,
|
|
enumerable: false
|
|
}
|
|
});
|
|
constr.__super = constrSuper;
|
|
constr.prototype = obj;
|
|
break;
|
|
case 43:
|
|
obj = stack.pop();
|
|
constr = stack.pop();
|
|
stack.push(as2InstanceOf(obj, constr) ? obj : null);
|
|
break;
|
|
case 44:
|
|
constr = stack.pop();
|
|
count = +stack.pop();
|
|
validateArgsCount(count, stack.length);
|
|
var interfaces = [];
|
|
for (i = 0; i < count; i++) {
|
|
interfaces.push(stack.pop());
|
|
}
|
|
constr.$interfaces = interfaces;
|
|
break;
|
|
case 143:
|
|
flags = stream.readUI8();
|
|
var catchIsRegisterFlag = !(!(flags & 4));
|
|
var finallyBlockFlag = !(!(flags & 2));
|
|
var catchBlockFlag = !(!(flags & 1));
|
|
var trySize = stream.readUI16();
|
|
var catchSize = stream.readUI16();
|
|
var finallySize = stream.readUI16();
|
|
var catchTarget = catchIsRegisterFlag ? stream.readUI8() : stream.readString();
|
|
nextPosition += trySize + catchSize + finallySize;
|
|
processTry(catchIsRegisterFlag, finallyBlockFlag, catchBlockFlag, catchTarget, stream.readBytes(trySize), stream.readBytes(catchSize), stream.readBytes(finallySize));
|
|
break;
|
|
case 42:
|
|
obj = stack.pop();
|
|
throw new AS2Error(obj);
|
|
case 45:
|
|
args = readArgs(stack);
|
|
stackItemsExpected++;
|
|
result = _global.fscommand.apply(null, args);
|
|
stack.push(result);
|
|
break;
|
|
case 137:
|
|
var mode = stream.readUI8();
|
|
break;
|
|
case 0:
|
|
return;
|
|
default:
|
|
throw new Error('Unknown action code: ' + actionCode);
|
|
}
|
|
stream.position = nextPosition;
|
|
recoveringFromError = false;
|
|
}
|
|
} catch (e) {
|
|
if (!AVM1_ERRORS_IGNORED && !currentContext.isTryCatchListening || e instanceof AS2CriticalError) {
|
|
throw e;
|
|
}
|
|
if (e instanceof AS2Error) {
|
|
throw e;
|
|
}
|
|
var AVM1_ERROR_TYPE = 1;
|
|
TelemetryService.reportTelemetry({
|
|
topic: 'error',
|
|
error: AVM1_ERROR_TYPE
|
|
});
|
|
stream.position = nextPosition;
|
|
if (stackItemsExpected > 0) {
|
|
while (stackItemsExpected--) {
|
|
stack.push(undefined);
|
|
}
|
|
}
|
|
if (!recoveringFromError) {
|
|
if (currentContext.errorsIgnored++ >= MAX_AVM1_ERRORS_LIMIT) {
|
|
throw new AS2CriticalError('long running script -- AVM1 errors limit is reached');
|
|
}
|
|
console.error('AVM1 error: ' + e);
|
|
avm2.exceptions.push({
|
|
source: 'avm1',
|
|
message: e.message,
|
|
stack: e.stack
|
|
});
|
|
recoveringFromError = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var ActionTracerFactory = function () {
|
|
var indentation = 0;
|
|
var tracer = {
|
|
print: function (position, actionCode, stack) {
|
|
var stackDump = [];
|
|
for (var q = 0; q < stack.length; q++) {
|
|
var item = stack[q];
|
|
stackDump.push(item && typeof item === 'object' ? '[' + (item.constructor && item.constructor.name ? item.constructor.name : 'Object') + ']' : item);
|
|
}
|
|
var indent = new Array(indentation + 1).join('..');
|
|
console.log('AVM1 trace: ' + indent + position + ': ' + ActionNamesMap[actionCode] + '(' + actionCode.toString(16) + '), ' + 'stack=' + stackDump);
|
|
},
|
|
indent: function () {
|
|
indentation++;
|
|
},
|
|
unindent: function () {
|
|
indentation--;
|
|
},
|
|
message: function (str) {
|
|
console.log('AVM1 trace: ------- ' + str);
|
|
}
|
|
};
|
|
var nullTracer = {
|
|
print: function () {
|
|
},
|
|
indent: function () {
|
|
},
|
|
unindent: function () {
|
|
},
|
|
message: function () {
|
|
}
|
|
};
|
|
function ActionTracerFactory() {
|
|
}
|
|
ActionTracerFactory.get = function () {
|
|
return AVM1_TRACE_ENABLED ? tracer : nullTracer;
|
|
};
|
|
return ActionTracerFactory;
|
|
}();
|
|
var ActionNamesMap = {
|
|
0: 'EOA',
|
|
4: 'ActionNextFrame',
|
|
5: 'ActionPreviousFrame',
|
|
6: 'ActionPlay',
|
|
7: 'ActionStop',
|
|
8: 'ActionToggleQuality',
|
|
9: 'ActionStopSounds',
|
|
10: 'ActionAdd',
|
|
11: 'ActionSubtract',
|
|
12: 'ActionMultiply',
|
|
13: 'ActionDivide',
|
|
14: 'ActionEquals',
|
|
15: 'ActionLess',
|
|
16: 'ActionAnd',
|
|
17: 'ActionOr',
|
|
18: 'ActionNot',
|
|
19: 'ActionStringEquals',
|
|
20: 'ActionStringLength',
|
|
21: 'ActionStringExtract',
|
|
23: 'ActionPop',
|
|
24: 'ActionToInteger',
|
|
28: 'ActionGetVariable',
|
|
29: 'ActionSetVariable',
|
|
32: 'ActionSetTarget2',
|
|
33: 'ActionStringAdd',
|
|
34: 'ActionGetProperty',
|
|
35: 'ActionSetProperty',
|
|
36: 'ActionCloneSprite',
|
|
37: 'ActionRemoveSprite',
|
|
38: 'ActionTrace',
|
|
39: 'ActionStartDrag',
|
|
40: 'ActionEndDrag',
|
|
41: 'ActionStringLess',
|
|
42: 'ActionThrow',
|
|
43: 'ActionCastOp',
|
|
44: 'ActionImplementsOp',
|
|
45: 'ActionFSCommand2',
|
|
48: 'ActionRandomNumber',
|
|
49: 'ActionMBStringLength',
|
|
50: 'ActionCharToAscii',
|
|
51: 'ActionAsciiToChar',
|
|
52: 'ActionGetTime',
|
|
53: 'ActionMBStringExtrac',
|
|
54: 'ActionMBCharToAscii',
|
|
55: 'ActionMBAsciiToChar',
|
|
58: 'ActionDelete',
|
|
59: 'ActionDelete2',
|
|
60: 'ActionDefineLocal',
|
|
61: 'ActionCallFunction',
|
|
62: 'ActionReturn',
|
|
63: 'ActionModulo',
|
|
64: 'ActionNewObject',
|
|
65: 'ActionDefineLocal2',
|
|
66: 'ActionInitArray',
|
|
67: 'ActionInitObject',
|
|
68: 'ActionTypeOf',
|
|
69: 'ActionTargetPath',
|
|
70: 'ActionEnumerate',
|
|
71: 'ActionAdd2',
|
|
72: 'ActionLess2',
|
|
73: 'ActionEquals2',
|
|
74: 'ActionToNumber',
|
|
75: 'ActionToString',
|
|
76: 'ActionPushDuplicate',
|
|
77: 'ActionStackSwap',
|
|
78: 'ActionGetMember',
|
|
79: 'ActionSetMember',
|
|
80: 'ActionIncrement',
|
|
81: 'ActionDecrement',
|
|
82: 'ActionCallMethod',
|
|
83: 'ActionNewMethod',
|
|
84: 'ActionInstanceOf',
|
|
85: 'ActionEnumerate2',
|
|
96: 'ActionBitAnd',
|
|
97: 'ActionBitOr',
|
|
98: 'ActionBitXor',
|
|
99: 'ActionBitLShift',
|
|
100: 'ActionBitRShift',
|
|
101: 'ActionBitURShift',
|
|
102: 'ActionStrictEquals',
|
|
103: 'ActionGreater',
|
|
104: 'ActionStringGreater',
|
|
105: 'ActionExtends',
|
|
129: 'ActionGotoFrame',
|
|
131: 'ActionGetURL',
|
|
135: 'ActionStoreRegister',
|
|
136: 'ActionConstantPool',
|
|
137: 'ActionStrictMode',
|
|
138: 'ActionWaitForFrame',
|
|
139: 'ActionSetTarget',
|
|
140: 'ActionGoToLabel',
|
|
141: 'ActionWaitForFrame2',
|
|
142: 'ActionDefineFunction',
|
|
143: 'ActionTry',
|
|
148: 'ActionWith',
|
|
150: 'ActionPush',
|
|
153: 'ActionJump',
|
|
154: 'ActionGetURL2',
|
|
155: 'ActionDefineFunction',
|
|
157: 'ActionIf',
|
|
158: 'ActionCall',
|
|
159: 'ActionGotoFrame2'
|
|
};
|
|
if (typeof GLOBAL !== 'undefined') {
|
|
GLOBAL.createBuiltinType = createBuiltinType;
|
|
GLOBAL.executeActions = executeActions;
|
|
GLOBAL.AS2Context = AS2Context;
|
|
}
|
|
var jsGlobal = function () {
|
|
return this || (1, eval)('this');
|
|
}();
|
|
var inBrowser = typeof console != 'undefined';
|
|
var release = true;
|
|
var debug = !true;
|
|
if (!jsGlobal.performance) {
|
|
jsGlobal.performance = {};
|
|
}
|
|
if (!jsGlobal.performance.now) {
|
|
jsGlobal.performance.now = dateNow;
|
|
}
|
|
function log(message) {
|
|
var optionalParams = [];
|
|
for (var _i = 0; _i < arguments.length - 1; _i++) {
|
|
optionalParams[_i] = arguments[_i + 1];
|
|
}
|
|
jsGlobal.print(message);
|
|
}
|
|
function warn(message) {
|
|
var optionalParams = [];
|
|
for (var _i = 0; _i < arguments.length - 1; _i++) {
|
|
optionalParams[_i] = arguments[_i + 1];
|
|
}
|
|
if (inBrowser) {
|
|
console.warn(message);
|
|
} else {
|
|
jsGlobal.print(message);
|
|
}
|
|
}
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (CharacterCodes) {
|
|
CharacterCodes[CharacterCodes['_0'] = 48] = '_0';
|
|
CharacterCodes[CharacterCodes['_1'] = 49] = '_1';
|
|
CharacterCodes[CharacterCodes['_2'] = 50] = '_2';
|
|
CharacterCodes[CharacterCodes['_3'] = 51] = '_3';
|
|
CharacterCodes[CharacterCodes['_4'] = 52] = '_4';
|
|
CharacterCodes[CharacterCodes['_5'] = 53] = '_5';
|
|
CharacterCodes[CharacterCodes['_6'] = 54] = '_6';
|
|
CharacterCodes[CharacterCodes['_7'] = 55] = '_7';
|
|
CharacterCodes[CharacterCodes['_8'] = 56] = '_8';
|
|
CharacterCodes[CharacterCodes['_9'] = 57] = '_9';
|
|
}(Shumway.CharacterCodes || (Shumway.CharacterCodes = {})));
|
|
var CharacterCodes = Shumway.CharacterCodes;
|
|
Shumway.UINT32_CHAR_BUFFER_LENGTH = 10;
|
|
Shumway.UINT32_MAX = 4294967295;
|
|
Shumway.UINT32_MAX_DIV_10 = 429496729;
|
|
Shumway.UINT32_MAX_MOD_10 = 5;
|
|
function isString(value) {
|
|
return typeof value === 'string';
|
|
}
|
|
Shumway.isString = isString;
|
|
function isFunction(value) {
|
|
return typeof value === 'function';
|
|
}
|
|
Shumway.isFunction = isFunction;
|
|
function isNumber(value) {
|
|
return typeof value === 'number';
|
|
}
|
|
Shumway.isNumber = isNumber;
|
|
function isNumberOrString(value) {
|
|
return typeof value === 'number' || typeof value === 'string';
|
|
}
|
|
Shumway.isNumberOrString = isNumberOrString;
|
|
function isObject(value) {
|
|
return typeof value === 'object' || typeof value === 'function';
|
|
}
|
|
Shumway.isObject = isObject;
|
|
function toNumber(x) {
|
|
return +x;
|
|
}
|
|
Shumway.toNumber = toNumber;
|
|
function isNumericString(value) {
|
|
return String(Number(value)) === value;
|
|
}
|
|
Shumway.isNumericString = isNumericString;
|
|
function isNumeric(value) {
|
|
if (typeof value === 'number') {
|
|
return true;
|
|
} else if (typeof value === 'string') {
|
|
return isIndex(value) || isNumericString(value);
|
|
} else {
|
|
Debug.notImplemented(typeof value);
|
|
}
|
|
}
|
|
Shumway.isNumeric = isNumeric;
|
|
function isIndex(value) {
|
|
var index = 0;
|
|
if (typeof value === 'number') {
|
|
index = value | 0;
|
|
if (value === index && index >= 0) {
|
|
return true;
|
|
}
|
|
return value >>> 0 === value;
|
|
}
|
|
if (typeof value !== 'string') {
|
|
return false;
|
|
}
|
|
var length = value.length;
|
|
if (length === 0) {
|
|
return false;
|
|
}
|
|
if (value === '0') {
|
|
return true;
|
|
}
|
|
if (length > Shumway.UINT32_CHAR_BUFFER_LENGTH) {
|
|
return false;
|
|
}
|
|
var i = 0;
|
|
index = value.charCodeAt(i++) - 48;
|
|
if (index < 1 || index > 9) {
|
|
return false;
|
|
}
|
|
var oldIndex = 0;
|
|
var c = 0;
|
|
while (i < length) {
|
|
c = value.charCodeAt(i++) - 48;
|
|
if (c < 0 || c > 9) {
|
|
return false;
|
|
}
|
|
oldIndex = index;
|
|
index = 10 * index + c;
|
|
}
|
|
if (oldIndex < Shumway.UINT32_MAX_DIV_10 || oldIndex === Shumway.UINT32_MAX_DIV_10 && c <= Shumway.UINT32_MAX_MOD_10) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
Shumway.isIndex = isIndex;
|
|
function isNullOrUndefined(value) {
|
|
return value == undefined;
|
|
}
|
|
Shumway.isNullOrUndefined = isNullOrUndefined;
|
|
(function (Debug) {
|
|
function backtrace() {
|
|
try {
|
|
throw new Error();
|
|
} catch (e) {
|
|
return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
|
|
}
|
|
}
|
|
Debug.backtrace = backtrace;
|
|
function error(message) {
|
|
if (!inBrowser) {
|
|
warn(Debug.backtrace());
|
|
}
|
|
throw new Error(message);
|
|
}
|
|
Debug.error = error;
|
|
function assert(condition) {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length - 1; _i++) {
|
|
args[_i] = arguments[_i + 1];
|
|
}
|
|
if (condition === '') {
|
|
condition = true;
|
|
}
|
|
if (!condition) {
|
|
var message = Array.prototype.slice.call(arguments);
|
|
message.shift();
|
|
Debug.error(message.join(''));
|
|
}
|
|
}
|
|
Debug.assert = assert;
|
|
function assertNotImplemented(condition, message) {
|
|
if (!condition) {
|
|
Debug.error('NotImplemented: ' + message);
|
|
}
|
|
}
|
|
Debug.assertNotImplemented = assertNotImplemented;
|
|
function warning(message) {
|
|
true;
|
|
}
|
|
Debug.warning = warning;
|
|
function notUsed(message) {
|
|
true;
|
|
}
|
|
Debug.notUsed = notUsed;
|
|
function notImplemented(message) {
|
|
true;
|
|
}
|
|
Debug.notImplemented = notImplemented;
|
|
function somewhatImplemented(message) {
|
|
Debug.warning('somewhatImplemented: ' + message);
|
|
}
|
|
Debug.somewhatImplemented = somewhatImplemented;
|
|
function unexpected(message) {
|
|
Debug.assert(false, 'Unexpected: ' + message);
|
|
}
|
|
Debug.unexpected = unexpected;
|
|
}(Shumway.Debug || (Shumway.Debug = {})));
|
|
var Debug = Shumway.Debug;
|
|
function getTicks() {
|
|
return performance.now();
|
|
}
|
|
Shumway.getTicks = getTicks;
|
|
(function (ArrayUtilities) {
|
|
function popManyInto(src, count, dst) {
|
|
true;
|
|
for (var i = count - 1; i >= 0; i--) {
|
|
dst[i] = src.pop();
|
|
}
|
|
dst.length = count;
|
|
}
|
|
ArrayUtilities.popManyInto = popManyInto;
|
|
}(Shumway.ArrayUtilities || (Shumway.ArrayUtilities = {})));
|
|
var ArrayUtilities = Shumway.ArrayUtilities;
|
|
(function (ObjectUtilities) {
|
|
function boxValue(value) {
|
|
if (Shumway.isNullOrUndefined(value) || Shumway.isObject(value)) {
|
|
return value;
|
|
}
|
|
return Object(value);
|
|
}
|
|
ObjectUtilities.boxValue = boxValue;
|
|
function toKeyValueArray(object) {
|
|
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
var array = [];
|
|
for (var k in object) {
|
|
if (hasOwnProperty.call(object, k)) {
|
|
array.push([
|
|
k,
|
|
object[k]
|
|
]);
|
|
}
|
|
}
|
|
return array;
|
|
}
|
|
ObjectUtilities.toKeyValueArray = toKeyValueArray;
|
|
function hasOwnProperty(object, name) {
|
|
return Object.prototype.hasOwnProperty.call(object, name);
|
|
}
|
|
ObjectUtilities.hasOwnProperty = hasOwnProperty;
|
|
function createEmptyObject() {
|
|
return Object.create(null);
|
|
}
|
|
ObjectUtilities.createEmptyObject = createEmptyObject;
|
|
function createMap() {
|
|
return Object.create(null);
|
|
}
|
|
ObjectUtilities.createMap = createMap;
|
|
function createArrayMap() {
|
|
return [];
|
|
}
|
|
ObjectUtilities.createArrayMap = createArrayMap;
|
|
function defineReadOnlyProperty(object, name, value) {
|
|
Object.defineProperty(object, name, {
|
|
value: value,
|
|
writable: false,
|
|
configurable: true,
|
|
enumerable: false
|
|
});
|
|
}
|
|
ObjectUtilities.defineReadOnlyProperty = defineReadOnlyProperty;
|
|
function getOwnPropertyDescriptors(object) {
|
|
var o = ObjectUtilities.createMap();
|
|
var properties = Object.getOwnPropertyNames(object);
|
|
for (var i = 0; i < properties.length; i++) {
|
|
o[properties[i]] = Object.getOwnPropertyDescriptor(object, properties[i]);
|
|
}
|
|
return o;
|
|
}
|
|
ObjectUtilities.getOwnPropertyDescriptors = getOwnPropertyDescriptors;
|
|
function cloneObject(object) {
|
|
var clone = ObjectUtilities.createEmptyObject();
|
|
for (var property in object) {
|
|
clone[property] = object[property];
|
|
}
|
|
return clone;
|
|
}
|
|
ObjectUtilities.cloneObject = cloneObject;
|
|
function copyProperties(object, template) {
|
|
for (var property in template) {
|
|
object[property] = template[property];
|
|
}
|
|
}
|
|
ObjectUtilities.copyProperties = copyProperties;
|
|
function getLatestGetterOrSetterPropertyDescriptor(object, name) {
|
|
var descriptor = {};
|
|
while (object) {
|
|
var tmp = Object.getOwnPropertyDescriptor(object, name);
|
|
if (tmp) {
|
|
descriptor.get = descriptor.get || tmp.get;
|
|
descriptor.set = descriptor.set || tmp.set;
|
|
}
|
|
if (descriptor.get && descriptor.set) {
|
|
break;
|
|
}
|
|
object = Object.getPrototypeOf(object);
|
|
}
|
|
return descriptor;
|
|
}
|
|
ObjectUtilities.getLatestGetterOrSetterPropertyDescriptor = getLatestGetterOrSetterPropertyDescriptor;
|
|
function defineNonEnumerableGetterOrSetter(obj, name, value, isGetter) {
|
|
var descriptor = ObjectUtilities.getLatestGetterOrSetterPropertyDescriptor(obj, name);
|
|
descriptor.configurable = true;
|
|
descriptor.enumerable = false;
|
|
if (isGetter) {
|
|
descriptor.get = value;
|
|
} else {
|
|
descriptor.set = value;
|
|
}
|
|
Object.defineProperty(obj, name, descriptor);
|
|
}
|
|
ObjectUtilities.defineNonEnumerableGetterOrSetter = defineNonEnumerableGetterOrSetter;
|
|
function defineNonEnumerableGetter(obj, name, getter) {
|
|
Object.defineProperty(obj, name, {
|
|
get: getter,
|
|
configurable: true,
|
|
enumerable: false
|
|
});
|
|
}
|
|
ObjectUtilities.defineNonEnumerableGetter = defineNonEnumerableGetter;
|
|
function defineNonEnumerableSetter(obj, name, setter) {
|
|
Object.defineProperty(obj, name, {
|
|
set: setter,
|
|
configurable: true,
|
|
enumerable: false
|
|
});
|
|
}
|
|
ObjectUtilities.defineNonEnumerableSetter = defineNonEnumerableSetter;
|
|
function defineNonEnumerableProperty(obj, name, value) {
|
|
Object.defineProperty(obj, name, {
|
|
value: value,
|
|
writable: true,
|
|
configurable: true,
|
|
enumerable: false
|
|
});
|
|
}
|
|
ObjectUtilities.defineNonEnumerableProperty = defineNonEnumerableProperty;
|
|
function defineNonEnumerableForwardingProperty(obj, name, otherName) {
|
|
Object.defineProperty(obj, name, {
|
|
get: FunctionUtilities.makeForwardingGetter(otherName),
|
|
set: FunctionUtilities.makeForwardingSetter(otherName),
|
|
writable: true,
|
|
configurable: true,
|
|
enumerable: false
|
|
});
|
|
}
|
|
ObjectUtilities.defineNonEnumerableForwardingProperty = defineNonEnumerableForwardingProperty;
|
|
function defineNewNonEnumerableProperty(obj, name, value) {
|
|
true;
|
|
ObjectUtilities.defineNonEnumerableProperty(obj, name, value);
|
|
}
|
|
ObjectUtilities.defineNewNonEnumerableProperty = defineNewNonEnumerableProperty;
|
|
}(Shumway.ObjectUtilities || (Shumway.ObjectUtilities = {})));
|
|
var ObjectUtilities = Shumway.ObjectUtilities;
|
|
(function (FunctionUtilities) {
|
|
function makeForwardingGetter(target) {
|
|
return new Function('return this["' + target + '"]');
|
|
}
|
|
FunctionUtilities.makeForwardingGetter = makeForwardingGetter;
|
|
function makeForwardingSetter(target) {
|
|
return new Function('value', 'this["' + target + '"] = value;');
|
|
}
|
|
FunctionUtilities.makeForwardingSetter = makeForwardingSetter;
|
|
function bindSafely(fn, object) {
|
|
true;
|
|
var f = fn.bind(object);
|
|
f.boundTo = object;
|
|
return f;
|
|
}
|
|
FunctionUtilities.bindSafely = bindSafely;
|
|
}(Shumway.FunctionUtilities || (Shumway.FunctionUtilities = {})));
|
|
var FunctionUtilities = Shumway.FunctionUtilities;
|
|
(function (StringUtilities) {
|
|
function toSafeString(value) {
|
|
if (typeof value === 'string') {
|
|
return '"' + value + '"';
|
|
}
|
|
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
return String(value);
|
|
}
|
|
return typeof value;
|
|
}
|
|
StringUtilities.toSafeString = toSafeString;
|
|
function toSafeArrayString(array) {
|
|
var str = [];
|
|
for (var i = 0; i < array.length; i++) {
|
|
str.push(toSafeString(array[i]));
|
|
}
|
|
return str.join(', ');
|
|
}
|
|
StringUtilities.toSafeArrayString = toSafeArrayString;
|
|
function utf8decode(str) {
|
|
var bytes = new Uint8Array(str.length * 4);
|
|
var b = 0;
|
|
for (var i = 0, j = str.length; i < j; i++) {
|
|
var code = str.charCodeAt(i);
|
|
if (code <= 127) {
|
|
bytes[b++] = code;
|
|
continue;
|
|
}
|
|
if (55296 <= code && code <= 56319) {
|
|
var codeLow = str.charCodeAt(i + 1);
|
|
if (56320 <= codeLow && codeLow <= 57343) {
|
|
code = ((code & 1023) << 10) + (codeLow & 1023) + 65536;
|
|
++i;
|
|
}
|
|
}
|
|
if ((code & 4292870144) !== 0) {
|
|
bytes[b++] = 248 | code >>> 24 & 3;
|
|
bytes[b++] = 128 | code >>> 18 & 63;
|
|
bytes[b++] = 128 | code >>> 12 & 63;
|
|
bytes[b++] = 128 | code >>> 6 & 63;
|
|
bytes[b++] = 128 | code & 63;
|
|
} else if ((code & 4294901760) !== 0) {
|
|
bytes[b++] = 240 | code >>> 18 & 7;
|
|
bytes[b++] = 128 | code >>> 12 & 63;
|
|
bytes[b++] = 128 | code >>> 6 & 63;
|
|
bytes[b++] = 128 | code & 63;
|
|
} else if ((code & 4294965248) !== 0) {
|
|
bytes[b++] = 224 | code >>> 12 & 15;
|
|
bytes[b++] = 128 | code >>> 6 & 63;
|
|
bytes[b++] = 128 | code & 63;
|
|
} else {
|
|
bytes[b++] = 192 | code >>> 6 & 31;
|
|
bytes[b++] = 128 | code & 63;
|
|
}
|
|
}
|
|
return bytes.subarray(0, b);
|
|
}
|
|
StringUtilities.utf8decode = utf8decode;
|
|
function utf8encode(bytes) {
|
|
var j = 0, str = '';
|
|
while (j < bytes.length) {
|
|
var b1 = bytes[j++] & 255;
|
|
if (b1 <= 127) {
|
|
str += String.fromCharCode(b1);
|
|
} else {
|
|
var currentPrefix = 192;
|
|
var validBits = 5;
|
|
do {
|
|
var mask = currentPrefix >> 1 | 128;
|
|
if ((b1 & mask) === currentPrefix)
|
|
break;
|
|
currentPrefix = currentPrefix >> 1 | 128;
|
|
--validBits;
|
|
} while (validBits >= 0);
|
|
if (validBits <= 0) {
|
|
str += String.fromCharCode(b1);
|
|
continue;
|
|
}
|
|
var code = b1 & (1 << validBits) - 1;
|
|
var invalid = false;
|
|
for (var i = 5; i >= validBits; --i) {
|
|
var bi = bytes[j++];
|
|
if ((bi & 192) != 128) {
|
|
invalid = true;
|
|
break;
|
|
}
|
|
code = code << 6 | bi & 63;
|
|
}
|
|
if (invalid) {
|
|
for (var k = j - (7 - i); k < j; ++k) {
|
|
str += String.fromCharCode(bytes[k] & 255);
|
|
}
|
|
continue;
|
|
}
|
|
if (code >= 65536) {
|
|
str += String.fromCharCode(code - 65536 >> 10 & 1023 | 55296, code & 1023 | 56320);
|
|
} else {
|
|
str += String.fromCharCode(code);
|
|
}
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
StringUtilities.utf8encode = utf8encode;
|
|
function base64ArrayBuffer(arrayBuffer) {
|
|
var base64 = '';
|
|
var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
var bytes = new Uint8Array(arrayBuffer);
|
|
var byteLength = bytes.byteLength;
|
|
var byteRemainder = byteLength % 3;
|
|
var mainLength = byteLength - byteRemainder;
|
|
var a, b, c, d;
|
|
var chunk;
|
|
for (var i = 0; i < mainLength; i = i + 3) {
|
|
chunk = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2];
|
|
a = (chunk & 16515072) >> 18;
|
|
b = (chunk & 258048) >> 12;
|
|
c = (chunk & 4032) >> 6;
|
|
d = chunk & 63;
|
|
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
|
|
}
|
|
if (byteRemainder == 1) {
|
|
chunk = bytes[mainLength];
|
|
a = (chunk & 252) >> 2;
|
|
b = (chunk & 3) << 4;
|
|
base64 += encodings[a] + encodings[b] + '==';
|
|
} else if (byteRemainder == 2) {
|
|
chunk = bytes[mainLength] << 8 | bytes[mainLength + 1];
|
|
a = (chunk & 64512) >> 10;
|
|
b = (chunk & 1008) >> 4;
|
|
c = (chunk & 15) << 2;
|
|
base64 += encodings[a] + encodings[b] + encodings[c] + '=';
|
|
}
|
|
return base64;
|
|
}
|
|
StringUtilities.base64ArrayBuffer = base64ArrayBuffer;
|
|
function escapeString(str) {
|
|
if (str !== undefined) {
|
|
str = str.replace(/[^\w$]/gi, '$');
|
|
if (/^\d/.test(str)) {
|
|
str = '$' + str;
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
StringUtilities.escapeString = escapeString;
|
|
function fromCharCodeArray(buffer) {
|
|
var str = '', SLICE = 1024 * 16;
|
|
for (var i = 0; i < buffer.length; i += SLICE) {
|
|
var chunk = Math.min(buffer.length - i, SLICE);
|
|
str += String.fromCharCode.apply(null, buffer.subarray(i, i + chunk));
|
|
}
|
|
return str;
|
|
}
|
|
StringUtilities.fromCharCodeArray = fromCharCodeArray;
|
|
var _encoding = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$_';
|
|
function variableLengthEncodeInt32(n) {
|
|
var e = _encoding;
|
|
var bitCount = 32 - IntegerUtilities.leadingZeros(n);
|
|
var l = Math.ceil(bitCount / 6);
|
|
var s = e[l];
|
|
for (var i = l - 1; i >= 0; i--) {
|
|
var offset = i * 6;
|
|
s += e[n >> offset & 63];
|
|
}
|
|
true;
|
|
return s;
|
|
}
|
|
StringUtilities.variableLengthEncodeInt32 = variableLengthEncodeInt32;
|
|
function toEncoding(n) {
|
|
return _encoding[n];
|
|
}
|
|
StringUtilities.toEncoding = toEncoding;
|
|
function fromEncoding(s) {
|
|
var c = s.charCodeAt(0);
|
|
var e = 0;
|
|
if (c >= 65 && c <= 90) {
|
|
return c - 65;
|
|
} else if (c >= 97 && c <= 122) {
|
|
return c - 71;
|
|
} else if (c >= 48 && c <= 57) {
|
|
return c + 4;
|
|
} else if (c === 36) {
|
|
return 62;
|
|
} else if (c === 95) {
|
|
return 63;
|
|
}
|
|
}
|
|
StringUtilities.fromEncoding = fromEncoding;
|
|
function variableLengthDecodeInt32(s) {
|
|
var l = StringUtilities.fromEncoding(s[0]);
|
|
var n = 0;
|
|
for (var i = 0; i < l; i++) {
|
|
var offset = (l - i - 1) * 6;
|
|
n |= StringUtilities.fromEncoding(s[1 + i]) << offset;
|
|
}
|
|
return n;
|
|
}
|
|
StringUtilities.variableLengthDecodeInt32 = variableLengthDecodeInt32;
|
|
}(Shumway.StringUtilities || (Shumway.StringUtilities = {})));
|
|
var StringUtilities = Shumway.StringUtilities;
|
|
(function (HashUtilities) {
|
|
var _md5R = new Uint8Array([
|
|
7,
|
|
12,
|
|
17,
|
|
22,
|
|
7,
|
|
12,
|
|
17,
|
|
22,
|
|
7,
|
|
12,
|
|
17,
|
|
22,
|
|
7,
|
|
12,
|
|
17,
|
|
22,
|
|
5,
|
|
9,
|
|
14,
|
|
20,
|
|
5,
|
|
9,
|
|
14,
|
|
20,
|
|
5,
|
|
9,
|
|
14,
|
|
20,
|
|
5,
|
|
9,
|
|
14,
|
|
20,
|
|
4,
|
|
11,
|
|
16,
|
|
23,
|
|
4,
|
|
11,
|
|
16,
|
|
23,
|
|
4,
|
|
11,
|
|
16,
|
|
23,
|
|
4,
|
|
11,
|
|
16,
|
|
23,
|
|
6,
|
|
10,
|
|
15,
|
|
21,
|
|
6,
|
|
10,
|
|
15,
|
|
21,
|
|
6,
|
|
10,
|
|
15,
|
|
21,
|
|
6,
|
|
10,
|
|
15,
|
|
21
|
|
]);
|
|
var _md5K = new Int32Array([
|
|
-680876936,
|
|
-389564586,
|
|
606105819,
|
|
-1044525330,
|
|
-176418897,
|
|
1200080426,
|
|
-1473231341,
|
|
-45705983,
|
|
1770035416,
|
|
-1958414417,
|
|
-42063,
|
|
-1990404162,
|
|
1804603682,
|
|
-40341101,
|
|
-1502002290,
|
|
1236535329,
|
|
-165796510,
|
|
-1069501632,
|
|
643717713,
|
|
-373897302,
|
|
-701558691,
|
|
38016083,
|
|
-660478335,
|
|
-405537848,
|
|
568446438,
|
|
-1019803690,
|
|
-187363961,
|
|
1163531501,
|
|
-1444681467,
|
|
-51403784,
|
|
1735328473,
|
|
-1926607734,
|
|
-378558,
|
|
-2022574463,
|
|
1839030562,
|
|
-35309556,
|
|
-1530992060,
|
|
1272893353,
|
|
-155497632,
|
|
-1094730640,
|
|
681279174,
|
|
-358537222,
|
|
-722521979,
|
|
76029189,
|
|
-640364487,
|
|
-421815835,
|
|
530742520,
|
|
-995338651,
|
|
-198630844,
|
|
1126891415,
|
|
-1416354905,
|
|
-57434055,
|
|
1700485571,
|
|
-1894986606,
|
|
-1051523,
|
|
-2054922799,
|
|
1873313359,
|
|
-30611744,
|
|
-1560198380,
|
|
1309151649,
|
|
-145523070,
|
|
-1120210379,
|
|
718787259,
|
|
-343485551
|
|
]);
|
|
function hashBytesTo32BitsMD5(data, offset, length) {
|
|
var r = _md5R;
|
|
var k = _md5K;
|
|
var h0 = 1732584193, h1 = -271733879, h2 = -1732584194, h3 = 271733878;
|
|
var paddedLength = length + 72 & ~63;
|
|
var padded = new Uint8Array(paddedLength);
|
|
var i, j, n;
|
|
for (i = 0; i < length; ++i) {
|
|
padded[i] = data[offset++];
|
|
}
|
|
padded[i++] = 128;
|
|
n = paddedLength - 8;
|
|
while (i < n) {
|
|
padded[i++] = 0;
|
|
}
|
|
padded[i++] = length << 3 & 255;
|
|
padded[i++] = length >> 5 & 255;
|
|
padded[i++] = length >> 13 & 255;
|
|
padded[i++] = length >> 21 & 255;
|
|
padded[i++] = length >>> 29 & 255;
|
|
padded[i++] = 0;
|
|
padded[i++] = 0;
|
|
padded[i++] = 0;
|
|
var w = new Int32Array(16);
|
|
for (i = 0; i < paddedLength;) {
|
|
for (j = 0; j < 16; ++j, i += 4) {
|
|
w[j] = padded[i] | padded[i + 1] << 8 | padded[i + 2] << 16 | padded[i + 3] << 24;
|
|
}
|
|
var a = h0, b = h1, c = h2, d = h3, f, g;
|
|
for (j = 0; j < 64; ++j) {
|
|
if (j < 16) {
|
|
f = b & c | ~b & d;
|
|
g = j;
|
|
} else if (j < 32) {
|
|
f = d & b | ~d & c;
|
|
g = 5 * j + 1 & 15;
|
|
} else if (j < 48) {
|
|
f = b ^ c ^ d;
|
|
g = 3 * j + 5 & 15;
|
|
} else {
|
|
f = c ^ (b | ~d);
|
|
g = 7 * j & 15;
|
|
}
|
|
var tmp = d, rotateArg = a + f + k[j] + w[g] | 0, rotate = r[j];
|
|
d = c;
|
|
c = b;
|
|
b = b + (rotateArg << rotate | rotateArg >>> 32 - rotate) | 0;
|
|
a = tmp;
|
|
}
|
|
h0 = h0 + a | 0;
|
|
h1 = h1 + b | 0;
|
|
h2 = h2 + c | 0;
|
|
h3 = h3 + d | 0;
|
|
}
|
|
return h0;
|
|
}
|
|
HashUtilities.hashBytesTo32BitsMD5 = hashBytesTo32BitsMD5;
|
|
function hashBytesTo32BitsAdler(data, offset, length) {
|
|
var a = 1;
|
|
var b = 0;
|
|
var end = offset + length;
|
|
for (var i = offset; i < end; ++i) {
|
|
a = (a + (data[i] & 255)) % 65521;
|
|
b = (b + a) % 65521;
|
|
}
|
|
return b << 16 | a;
|
|
}
|
|
HashUtilities.hashBytesTo32BitsAdler = hashBytesTo32BitsAdler;
|
|
}(Shumway.HashUtilities || (Shumway.HashUtilities = {})));
|
|
var HashUtilities = Shumway.HashUtilities;
|
|
(function (IntegerUtilities) {
|
|
function bitCount(i) {
|
|
i = i - (i >> 1 & 1431655765);
|
|
i = (i & 858993459) + (i >> 2 & 858993459);
|
|
return (i + (i >> 4) & 252645135) * 16843009 >> 24;
|
|
}
|
|
IntegerUtilities.bitCount = bitCount;
|
|
function ones(i) {
|
|
i = i - (i >> 1 & 1431655765);
|
|
i = (i & 858993459) + (i >> 2 & 858993459);
|
|
return (i + (i >> 4) & 252645135) * 16843009 >> 24;
|
|
}
|
|
IntegerUtilities.ones = ones;
|
|
function leadingZeros(i) {
|
|
i |= i >> 1;
|
|
i |= i >> 2;
|
|
i |= i >> 4;
|
|
i |= i >> 8;
|
|
i |= i >> 16;
|
|
return 32 - IntegerUtilities.ones(i);
|
|
}
|
|
IntegerUtilities.leadingZeros = leadingZeros;
|
|
function trailingZeros(i) {
|
|
return IntegerUtilities.ones((i & -i) - 1);
|
|
}
|
|
IntegerUtilities.trailingZeros = trailingZeros;
|
|
function getFlags(i, flags) {
|
|
var str = '';
|
|
for (var i = 0; i < flags.length; i++) {
|
|
if (i & 1 << i) {
|
|
str += flags[i] + ' ';
|
|
}
|
|
}
|
|
if (str.length === 0) {
|
|
return '';
|
|
}
|
|
return str.trim();
|
|
}
|
|
IntegerUtilities.getFlags = getFlags;
|
|
function isPowerOfTwo(x) {
|
|
return x && (x & x - 1) === 0;
|
|
}
|
|
IntegerUtilities.isPowerOfTwo = isPowerOfTwo;
|
|
}(Shumway.IntegerUtilities || (Shumway.IntegerUtilities = {})));
|
|
var IntegerUtilities = Shumway.IntegerUtilities;
|
|
var IndentingWriter = function () {
|
|
function IndentingWriter(suppressOutput, outFn) {
|
|
if (typeof suppressOutput === 'undefined') {
|
|
suppressOutput = false;
|
|
}
|
|
this._tab = ' ';
|
|
this._padding = '';
|
|
this._suppressOutput = suppressOutput;
|
|
this._out = outFn || IndentingWriter._consoleOutFn;
|
|
}
|
|
IndentingWriter.prototype.writeLn = function (str) {
|
|
if (!this._suppressOutput) {
|
|
this._out(this._padding + str);
|
|
}
|
|
};
|
|
IndentingWriter.prototype.writeLns = function (str) {
|
|
var lines = str.split('\n');
|
|
for (var i = 0; i < lines.length; i++) {
|
|
this.writeLn(lines[i]);
|
|
}
|
|
};
|
|
IndentingWriter.prototype.debugLn = function (str) {
|
|
this.colorLn(IndentingWriter.PURPLE, str);
|
|
};
|
|
IndentingWriter.prototype.yellowLn = function (str) {
|
|
this.colorLn(IndentingWriter.YELLOW, str);
|
|
};
|
|
IndentingWriter.prototype.greenLn = function (str) {
|
|
this.colorLn(IndentingWriter.GREEN, str);
|
|
};
|
|
IndentingWriter.prototype.redLn = function (str) {
|
|
this.colorLn(IndentingWriter.RED, str);
|
|
};
|
|
IndentingWriter.prototype.colorLn = function (color, str) {
|
|
if (!this._suppressOutput) {
|
|
if (!inBrowser) {
|
|
this._out(this._padding + color + str + IndentingWriter.ENDC);
|
|
} else {
|
|
this._out(this._padding + str);
|
|
}
|
|
}
|
|
};
|
|
IndentingWriter.prototype.enter = function (str) {
|
|
if (!this._suppressOutput) {
|
|
this._out(this._padding + str);
|
|
}
|
|
this.indent();
|
|
};
|
|
IndentingWriter.prototype.leaveAndEnter = function (str) {
|
|
this.leave(str);
|
|
this.indent();
|
|
};
|
|
IndentingWriter.prototype.leave = function (str) {
|
|
this.outdent();
|
|
if (!this._suppressOutput) {
|
|
this._out(this._padding + str);
|
|
}
|
|
};
|
|
IndentingWriter.prototype.indent = function () {
|
|
this._padding += this._tab;
|
|
};
|
|
IndentingWriter.prototype.outdent = function () {
|
|
if (this._padding.length > 0) {
|
|
this._padding = this._padding.substring(0, this._padding.length - this._tab.length);
|
|
}
|
|
};
|
|
IndentingWriter.prototype.writeArray = function (arr, detailed, noNumbers) {
|
|
if (typeof detailed === 'undefined') {
|
|
detailed = false;
|
|
}
|
|
if (typeof noNumbers === 'undefined') {
|
|
noNumbers = false;
|
|
}
|
|
detailed = detailed || false;
|
|
for (var i = 0, j = arr.length; i < j; i++) {
|
|
var prefix = '';
|
|
if (detailed) {
|
|
if (arr[i] === null) {
|
|
prefix = 'null';
|
|
} else if (arr[i] === undefined) {
|
|
prefix = 'undefined';
|
|
} else {
|
|
prefix = arr[i].constructor.name;
|
|
}
|
|
prefix += ' ';
|
|
}
|
|
var number = noNumbers ? '' : ('' + i).padRight(' ', 4);
|
|
this.writeLn(number + prefix + arr[i]);
|
|
}
|
|
};
|
|
IndentingWriter.PURPLE = '\x1b[94m';
|
|
IndentingWriter.YELLOW = '\x1b[93m';
|
|
IndentingWriter.GREEN = '\x1b[92m';
|
|
IndentingWriter.RED = '\x1b[91m';
|
|
IndentingWriter.ENDC = '\x1b[0m';
|
|
IndentingWriter._consoleOutFn = inBrowser ? console.info.bind(console) : print;
|
|
return IndentingWriter;
|
|
}();
|
|
Shumway.IndentingWriter = IndentingWriter;
|
|
var SortedListNode = function () {
|
|
function SortedListNode(value, next) {
|
|
this.value = value;
|
|
this.next = next;
|
|
}
|
|
return SortedListNode;
|
|
}();
|
|
var SortedList = function () {
|
|
function SortedList(compare) {
|
|
true;
|
|
this._compare = compare;
|
|
this._head = null;
|
|
this._length = 0;
|
|
}
|
|
SortedList.prototype.push = function (value) {
|
|
true;
|
|
this._length++;
|
|
if (!this._head) {
|
|
this._head = new SortedListNode(value, null);
|
|
return;
|
|
}
|
|
var curr = this._head;
|
|
var prev = null;
|
|
var node = new SortedListNode(value, null);
|
|
var compare = this._compare;
|
|
while (curr) {
|
|
if (compare(curr.value, node.value) > 0) {
|
|
if (prev) {
|
|
node.next = curr;
|
|
prev.next = node;
|
|
} else {
|
|
node.next = this._head;
|
|
this._head = node;
|
|
}
|
|
return;
|
|
}
|
|
prev = curr;
|
|
curr = curr.next;
|
|
}
|
|
prev.next = node;
|
|
};
|
|
SortedList.prototype.forEach = function (visitor) {
|
|
var curr = this._head;
|
|
var last = null;
|
|
while (curr) {
|
|
var result = visitor(curr.value);
|
|
if (result === SortedList.RETURN) {
|
|
return;
|
|
} else if (result === SortedList.DELETE) {
|
|
if (!last) {
|
|
curr = this._head = this._head.next;
|
|
} else {
|
|
curr = last.next = curr.next;
|
|
}
|
|
} else {
|
|
last = curr;
|
|
curr = curr.next;
|
|
}
|
|
}
|
|
};
|
|
SortedList.prototype.isEmpty = function () {
|
|
return !this._head;
|
|
};
|
|
SortedList.prototype.pop = function () {
|
|
if (!this._head) {
|
|
return undefined;
|
|
}
|
|
this._length--;
|
|
var ret = this._head;
|
|
this._head = this._head.next;
|
|
return ret.value;
|
|
};
|
|
SortedList.prototype.contains = function (value) {
|
|
var curr = this._head;
|
|
while (curr) {
|
|
if (curr.value === value) {
|
|
return true;
|
|
}
|
|
curr = curr.next;
|
|
}
|
|
return false;
|
|
};
|
|
SortedList.prototype.toString = function () {
|
|
var str = '[';
|
|
var curr = this._head;
|
|
while (curr) {
|
|
str += curr.value.toString();
|
|
curr = curr.next;
|
|
if (curr) {
|
|
str += ',';
|
|
}
|
|
}
|
|
str += ']';
|
|
return str;
|
|
};
|
|
SortedList.RETURN = 1;
|
|
SortedList.DELETE = 2;
|
|
return SortedList;
|
|
}();
|
|
Shumway.SortedList = SortedList;
|
|
var CIRCULAR_BUFFER_MASK = 4095;
|
|
var CIRCULAR_BUFFER_SIZE = 4096;
|
|
var CircularBuffer = function () {
|
|
function CircularBuffer(Type) {
|
|
this.index = 0;
|
|
this.start = 0;
|
|
this.array = new Type(CIRCULAR_BUFFER_SIZE);
|
|
}
|
|
CircularBuffer.prototype.get = function (i) {
|
|
return this.array[i];
|
|
};
|
|
CircularBuffer.prototype.forEachInReverse = function (visitor) {
|
|
if (this.isEmpty()) {
|
|
return;
|
|
}
|
|
var i = this.index === 0 ? CIRCULAR_BUFFER_SIZE - 1 : this.index - 1;
|
|
while (i !== this.start) {
|
|
if (visitor(this.array[i], i)) {
|
|
break;
|
|
}
|
|
i = i === 0 ? CIRCULAR_BUFFER_SIZE - 1 : i - 1;
|
|
}
|
|
};
|
|
CircularBuffer.prototype.write = function (value) {
|
|
this.array[this.index] = value;
|
|
this.index = this.index + 1 & CIRCULAR_BUFFER_MASK;
|
|
if (this.index === this.start) {
|
|
this.start = this.start + 1 & CIRCULAR_BUFFER_MASK;
|
|
}
|
|
};
|
|
CircularBuffer.prototype.isFull = function () {
|
|
return (this.index + 1 & CIRCULAR_BUFFER_MASK) === this.start;
|
|
};
|
|
CircularBuffer.prototype.isEmpty = function () {
|
|
return this.index === this.start;
|
|
};
|
|
return CircularBuffer;
|
|
}();
|
|
Shumway.CircularBuffer = CircularBuffer;
|
|
}(Shumway || (Shumway = {})));
|
|
var assert = Shumway.Debug.assert;
|
|
var IndentingWriter = Shumway.IndentingWriter;
|
|
var assert = Shumway.Debug.assert;
|
|
var $DEBUG;
|
|
var release = true;
|
|
var c4CoerceNonPrimitiveParameters = false;
|
|
var c4CoerceNonPrimitive = false;
|
|
var c4AsTypeLate = true;
|
|
var error = Shumway.Debug.error;
|
|
var assertNotImplemented = Shumway.Debug.assertNotImplemented;
|
|
var warning = Shumway.Debug.warning;
|
|
var notImplemented = Shumway.Debug.notImplemented;
|
|
var somewhatImplemented = Shumway.Debug.somewhatImplemented;
|
|
var unexpected = Shumway.Debug.unexpected;
|
|
var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty;
|
|
var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject;
|
|
var makeForwardingGetter = Shumway.FunctionUtilities.makeForwardingGetter;
|
|
var makeForwardingSetter = Shumway.FunctionUtilities.makeForwardingSetter;
|
|
var bindSafely = Shumway.FunctionUtilities.bindSafely;
|
|
var cloneObject = Shumway.ObjectUtilities.cloneObject;
|
|
var copyProperties = Shumway.ObjectUtilities.copyProperties;
|
|
var toSafeString = Shumway.StringUtilities.toSafeString;
|
|
var toSafeArrayString = Shumway.StringUtilities.toSafeArrayString;
|
|
var getLatestGetterOrSetterPropertyDescriptor = Shumway.ObjectUtilities.getLatestGetterOrSetterPropertyDescriptor;
|
|
var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter;
|
|
var defineNonEnumerableGetter = Shumway.ObjectUtilities.defineNonEnumerableGetter;
|
|
var defineNonEnumerableSetter = Shumway.ObjectUtilities.defineNonEnumerableSetter;
|
|
var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty;
|
|
var defineNonEnumerableForwardingProperty = Shumway.ObjectUtilities.defineNonEnumerableForwardingProperty;
|
|
var defineNewNonEnumerableProperty = Shumway.ObjectUtilities.defineNewNonEnumerableProperty;
|
|
var isNumeric = Shumway.isNumeric;
|
|
var isNullOrUndefined = Shumway.isNullOrUndefined;
|
|
var isPowerOfTwo = Shumway.IntegerUtilities.isPowerOfTwo;
|
|
function time(fn, count) {
|
|
var start = performance.now();
|
|
for (var i = 0; i < count; i++) {
|
|
fn();
|
|
}
|
|
var time = (performance.now() - start) / count;
|
|
console.info('Took: ' + time.toFixed(2) + 'ms.');
|
|
return time;
|
|
}
|
|
function clamp(x, min, max) {
|
|
if (x < min) {
|
|
return min;
|
|
} else if (x > max) {
|
|
return max;
|
|
}
|
|
return x;
|
|
}
|
|
var fromCharCodeArray = Shumway.StringUtilities.fromCharCodeArray;
|
|
function hasOwnProperty(object, name) {
|
|
return Object.prototype.hasOwnProperty.call(object, name);
|
|
}
|
|
var toKeyValueArray = Shumway.ObjectUtilities.toKeyValueArray;
|
|
var boxValue = Shumway.ObjectUtilities.boxValue;
|
|
function isObject(value) {
|
|
return typeof value === 'object' || typeof value === 'function';
|
|
}
|
|
function isString(value) {
|
|
return typeof value === 'string';
|
|
}
|
|
function isFunction(value) {
|
|
return typeof value === 'function';
|
|
}
|
|
function isNumber(value) {
|
|
return typeof value === 'number';
|
|
}
|
|
function toNumber(x) {
|
|
return +x;
|
|
}
|
|
function setBitFlags(flags, flag, value) {
|
|
return value ? flags | flag : flags & ~flag;
|
|
}
|
|
function getBitFlags(flags, flag) {
|
|
return !(!(flags & flag));
|
|
}
|
|
(function () {
|
|
function extendBuiltin(proto, prop, f) {
|
|
if (!proto[prop]) {
|
|
Object.defineProperty(proto, prop, {
|
|
value: f,
|
|
writable: true,
|
|
configurable: true,
|
|
enumerable: false
|
|
});
|
|
}
|
|
}
|
|
var Sp = String.prototype;
|
|
function removeColors(s) {
|
|
return s.replace(/\033\[[0-9]*m/g, '');
|
|
}
|
|
extendBuiltin(Sp, 'padRight', function (c, n) {
|
|
var str = this;
|
|
var length = removeColors(str).length;
|
|
if (!c || length >= n) {
|
|
return str;
|
|
}
|
|
var max = (n - length) / c.length;
|
|
for (var i = 0; i < max; i++) {
|
|
str += c;
|
|
}
|
|
return str;
|
|
});
|
|
extendBuiltin(Sp, 'padLeft', function (c, n) {
|
|
var str = this;
|
|
var length = str.length;
|
|
if (!c || length >= n) {
|
|
return str;
|
|
}
|
|
var max = (n - length) / c.length;
|
|
for (var i = 0; i < max; i++) {
|
|
str = c + str;
|
|
}
|
|
return str;
|
|
});
|
|
extendBuiltin(Sp, 'trim', function () {
|
|
return this.replace(/^\s+|\s+$/g, '');
|
|
});
|
|
extendBuiltin(Sp, 'endsWith', function (str) {
|
|
return this.indexOf(str, this.length - str.length) !== -1;
|
|
});
|
|
var Ap = Array.prototype;
|
|
extendBuiltin(Ap, 'popMany', function (count) {
|
|
true;
|
|
var start = this.length - count;
|
|
var res = this.slice(start, this.length);
|
|
this.splice(start, count);
|
|
return res;
|
|
});
|
|
extendBuiltin(Ap, 'pushMany', function (array) {
|
|
for (var i = 0; i < array.length; i++) {
|
|
this.push(array[i]);
|
|
}
|
|
});
|
|
extendBuiltin(Ap, 'clone', function () {
|
|
return this.slice(0);
|
|
});
|
|
extendBuiltin(Ap, 'first', function () {
|
|
true;
|
|
return this[0];
|
|
});
|
|
extendBuiltin(Ap, 'last', function () {
|
|
true;
|
|
return this[this.length - 1];
|
|
});
|
|
extendBuiltin(Ap, 'peek', function () {
|
|
true;
|
|
return this[this.length - 1];
|
|
});
|
|
extendBuiltin(Ap, 'empty', function () {
|
|
return this.length === 0;
|
|
});
|
|
extendBuiltin(Ap, 'pushUnique', function (v) {
|
|
for (var i = 0, j = this.length; i < j; i++) {
|
|
if (this[i] === v) {
|
|
return;
|
|
}
|
|
}
|
|
this.push(v);
|
|
});
|
|
var uniquesMap;
|
|
if (typeof Map !== 'undefined' && (uniquesMap = new Map()).clear) {
|
|
extendBuiltin(Ap, 'unique', function () {
|
|
var unique = [];
|
|
for (var i = 0; i < this.length; i++) {
|
|
if (uniquesMap.has(this[i])) {
|
|
continue;
|
|
}
|
|
unique.push(this[i]);
|
|
uniquesMap.set(this[i], true);
|
|
}
|
|
uniquesMap.clear();
|
|
return unique;
|
|
});
|
|
} else {
|
|
extendBuiltin(Ap, 'unique', function () {
|
|
var unique = [];
|
|
for (var i = 0; i < this.length; i++) {
|
|
unique.pushUnique(this[i]);
|
|
}
|
|
return unique;
|
|
});
|
|
}
|
|
extendBuiltin(Ap, 'replace', function (x, y) {
|
|
if (x === y) {
|
|
return 0;
|
|
}
|
|
var count = 0;
|
|
for (var i = 0; i < this.length; i++) {
|
|
if (this[i] === x) {
|
|
this[i] = y;
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
});
|
|
extendBuiltin(Ap, 'count', function (x) {
|
|
var count = 0;
|
|
for (var i = 0; i < this.length; i++) {
|
|
if (this[i] === x) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
});
|
|
extendBuiltin(Ap, 'notEmpty', function () {
|
|
return this.length > 0;
|
|
});
|
|
extendBuiltin(Ap, 'contains', function (val) {
|
|
return this.indexOf(val) >= 0;
|
|
});
|
|
extendBuiltin(Ap, 'top', function () {
|
|
return this.length && this[this.length - 1];
|
|
});
|
|
extendBuiltin(Ap, 'mapWithIndex', function (fn) {
|
|
var arr = [];
|
|
for (var i = 0; i < this.length; i++) {
|
|
arr.push(fn(this[i], i));
|
|
}
|
|
return arr;
|
|
});
|
|
}());
|
|
var utf8decode = Shumway.StringUtilities.utf8decode;
|
|
var utf8encode = Shumway.StringUtilities.utf8encode;
|
|
var escapeString = Shumway.StringUtilities.escapeString;
|
|
var bitCount = Shumway.IntegerUtilities.bitCount;
|
|
var ones = Shumway.IntegerUtilities.ones;
|
|
var leadingZeros = Shumway.IntegerUtilities.leadingZeros;
|
|
var trailingZeros = Shumway.IntegerUtilities.trailingZeros;
|
|
var getFlags = Shumway.IntegerUtilities.getFlags;
|
|
function BitSetFunctor(length) {
|
|
var ADDRESS_BITS_PER_WORD = 5;
|
|
var BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
|
|
var BIT_INDEX_MASK = BITS_PER_WORD - 1;
|
|
var SIZE = length + (BITS_PER_WORD - 1) >> ADDRESS_BITS_PER_WORD << ADDRESS_BITS_PER_WORD;
|
|
function BitSet() {
|
|
this.count = 0;
|
|
this.dirty = 0;
|
|
this.size = SIZE;
|
|
this.bits = new Uint32Array(SIZE >> ADDRESS_BITS_PER_WORD);
|
|
}
|
|
function BitSetS() {
|
|
this.count = 0;
|
|
this.dirty = 0;
|
|
this.size = SIZE;
|
|
this.bits = 0;
|
|
}
|
|
var singleword = SIZE >> ADDRESS_BITS_PER_WORD === 1;
|
|
var Ctor = singleword ? BitSetS : BitSet;
|
|
Ctor.ADDRESS_BITS_PER_WORD = ADDRESS_BITS_PER_WORD;
|
|
Ctor.BITS_PER_WORD = BITS_PER_WORD;
|
|
Ctor.BIT_INDEX_MASK = BIT_INDEX_MASK;
|
|
Ctor.singleword = singleword;
|
|
BitSet.prototype = {
|
|
recount: function recount() {
|
|
if (!this.dirty) {
|
|
return;
|
|
}
|
|
var bits = this.bits;
|
|
var c = 0;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var v = bits[i];
|
|
v = v - (v >> 1 & 1431655765);
|
|
v = (v & 858993459) + (v >> 2 & 858993459);
|
|
c += (v + (v >> 4) & 252645135) * 16843009 >> 24;
|
|
}
|
|
this.count = c;
|
|
this.dirty = 0;
|
|
},
|
|
set: function set(i) {
|
|
var n = i >> ADDRESS_BITS_PER_WORD;
|
|
var old = this.bits[n];
|
|
var b = old | 1 << (i & BIT_INDEX_MASK);
|
|
this.bits[n] = b;
|
|
this.dirty |= old ^ b;
|
|
},
|
|
setAll: function setAll() {
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
bits[i] = 4294967295;
|
|
}
|
|
this.count = this.size;
|
|
this.dirty = 0;
|
|
},
|
|
assign: function assign(set) {
|
|
this.count = set.count;
|
|
this.dirty = set.dirty;
|
|
this.size = set.size;
|
|
for (var i = 0, j = this.bits.length; i < j; i++) {
|
|
this.bits[i] = set.bits[i];
|
|
}
|
|
},
|
|
clear: function clear(i) {
|
|
var n = i >> ADDRESS_BITS_PER_WORD;
|
|
var old = this.bits[n];
|
|
var b = old & ~(1 << (i & BIT_INDEX_MASK));
|
|
this.bits[n] = b;
|
|
this.dirty |= old ^ b;
|
|
},
|
|
get: function get(i) {
|
|
var word = this.bits[i >> ADDRESS_BITS_PER_WORD];
|
|
return (word & 1 << (i & BIT_INDEX_MASK)) !== 0;
|
|
},
|
|
clearAll: function clearAll() {
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
bits[i] = 0;
|
|
}
|
|
this.count = 0;
|
|
this.dirty = 0;
|
|
},
|
|
_union: function _union(other) {
|
|
var dirty = this.dirty;
|
|
var bits = this.bits;
|
|
var otherBits = other.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var old = bits[i];
|
|
var b = old | otherBits[i];
|
|
bits[i] = b;
|
|
dirty |= old ^ b;
|
|
}
|
|
this.dirty = dirty;
|
|
},
|
|
intersect: function intersect(other) {
|
|
var dirty = this.dirty;
|
|
var bits = this.bits;
|
|
var otherBits = other.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var old = bits[i];
|
|
var b = old & otherBits[i];
|
|
bits[i] = b;
|
|
dirty |= old ^ b;
|
|
}
|
|
this.dirty = dirty;
|
|
},
|
|
subtract: function subtract(other) {
|
|
var dirty = this.dirty;
|
|
var bits = this.bits;
|
|
var otherBits = other.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var old = bits[i];
|
|
var b = old & ~otherBits[i];
|
|
bits[i] = b;
|
|
dirty |= old ^ b;
|
|
}
|
|
this.dirty = dirty;
|
|
},
|
|
negate: function negate() {
|
|
var dirty = this.dirty;
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var old = bits[i];
|
|
var b = ~old;
|
|
bits[i] = b;
|
|
dirty |= old ^ b;
|
|
}
|
|
this.dirty = dirty;
|
|
},
|
|
forEach: function forEach(fn) {
|
|
true;
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var word = bits[i];
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
fn(i * BITS_PER_WORD + k);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
toArray: function toArray() {
|
|
var set = [];
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var word = bits[i];
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
set.push(i * BITS_PER_WORD + k);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return set;
|
|
},
|
|
equals: function equals(other) {
|
|
if (this.size !== other.size) {
|
|
return false;
|
|
}
|
|
var bits = this.bits;
|
|
var otherBits = other.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
if (bits[i] !== otherBits[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
contains: function contains(other) {
|
|
if (this.size !== other.size) {
|
|
return false;
|
|
}
|
|
var bits = this.bits;
|
|
var otherBits = other.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
if ((bits[i] | otherBits[i]) !== bits[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
toBitString: function toBitString(on, off) {
|
|
on = on || '1';
|
|
off = off || '0';
|
|
var str = '';
|
|
for (var i = 0; i < length; i++) {
|
|
str += this.get(i) ? on : off;
|
|
}
|
|
return str;
|
|
},
|
|
length: length,
|
|
toString: function toString(names) {
|
|
var set = [];
|
|
for (var i = 0; i < length; i++) {
|
|
if (this.get(i)) {
|
|
set.push(names ? names[i] : i);
|
|
}
|
|
}
|
|
return set.join(', ');
|
|
},
|
|
isEmpty: function isEmpty() {
|
|
this.recount();
|
|
return this.count === 0;
|
|
},
|
|
clone: function clone() {
|
|
var set = new BitSet();
|
|
set._union(this);
|
|
return set;
|
|
}
|
|
};
|
|
BitSetS.prototype = {
|
|
recount: function recount() {
|
|
if (!this.dirty) {
|
|
return;
|
|
}
|
|
var c = 0;
|
|
var v = this.bits;
|
|
v = v - (v >> 1 & 1431655765);
|
|
v = (v & 858993459) + (v >> 2 & 858993459);
|
|
c += (v + (v >> 4) & 252645135) * 16843009 >> 24;
|
|
this.count = c;
|
|
this.dirty = 0;
|
|
},
|
|
set: function set(i) {
|
|
var old = this.bits;
|
|
var b = old | 1 << (i & BIT_INDEX_MASK);
|
|
this.bits = b;
|
|
this.dirty |= old ^ b;
|
|
},
|
|
setAll: function setAll() {
|
|
this.bits = 4294967295;
|
|
this.count = this.size;
|
|
this.dirty = 0;
|
|
},
|
|
assign: function assign(set) {
|
|
this.count = set.count;
|
|
this.dirty = set.dirty;
|
|
this.size = set.size;
|
|
this.bits = set.bits;
|
|
},
|
|
clear: function clear(i) {
|
|
var old = this.bits;
|
|
var b = old & ~(1 << (i & BIT_INDEX_MASK));
|
|
this.bits = b;
|
|
this.dirty |= old ^ b;
|
|
},
|
|
get: function get(i) {
|
|
return (this.bits & 1 << (i & BIT_INDEX_MASK)) !== 0;
|
|
},
|
|
clearAll: function clearAll() {
|
|
this.bits = 0;
|
|
this.count = 0;
|
|
this.dirty = 0;
|
|
},
|
|
_union: function _union(other) {
|
|
var old = this.bits;
|
|
var b = old | other.bits;
|
|
this.bits = b;
|
|
this.dirty = old ^ b;
|
|
},
|
|
intersect: function intersect(other) {
|
|
var old = this.bits;
|
|
var b = old & other.bits;
|
|
this.bits = b;
|
|
this.dirty = old ^ b;
|
|
},
|
|
subtract: function subtract(other) {
|
|
var old = this.bits;
|
|
var b = old & ~other.bits;
|
|
this.bits = b;
|
|
this.dirty = old ^ b;
|
|
},
|
|
negate: function negate() {
|
|
var old = this.bits;
|
|
var b = ~old;
|
|
this.bits = b;
|
|
this.dirty = old ^ b;
|
|
},
|
|
forEach: function forEach(fn) {
|
|
true;
|
|
var word = this.bits;
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
fn(k);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
toArray: function toArray() {
|
|
var set = [];
|
|
var word = this.bits;
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
set.push(k);
|
|
}
|
|
}
|
|
}
|
|
return set;
|
|
},
|
|
equals: function equals(other) {
|
|
return this.bits === other.bits;
|
|
},
|
|
contains: function contains(other) {
|
|
var bits = this.bits;
|
|
return (bits | other.bits) === bits;
|
|
},
|
|
isEmpty: function isEmpty() {
|
|
this.recount();
|
|
return this.count === 0;
|
|
},
|
|
clone: function clone() {
|
|
var set = new BitSetS();
|
|
set._union(this);
|
|
return set;
|
|
},
|
|
toBitString: BitSet.prototype.toBitString,
|
|
toString: BitSet.prototype.toString,
|
|
length: length
|
|
};
|
|
return Ctor;
|
|
}
|
|
var Map = function () {
|
|
function map() {
|
|
this.elements = {};
|
|
}
|
|
map.prototype.set = function set(k, v) {
|
|
this.elements[k] = v;
|
|
};
|
|
map.prototype.get = function get(k) {
|
|
if (this.has(k)) {
|
|
return this.elements[k];
|
|
}
|
|
return undefined;
|
|
};
|
|
map.prototype.has = function has(k) {
|
|
return Object.prototype.hasOwnProperty.call(this.elements, k);
|
|
};
|
|
map.prototype.remove = function remove(k) {
|
|
if (this.has(k)) {
|
|
delete this.elements[k];
|
|
}
|
|
};
|
|
return map;
|
|
}();
|
|
(function checkWeakMap() {
|
|
if (typeof this.WeakMap === 'function')
|
|
return;
|
|
var id = 0;
|
|
function WeakMap() {
|
|
this.id = '$weakmap' + id++;
|
|
}
|
|
;
|
|
WeakMap.prototype = {
|
|
has: function (obj) {
|
|
return obj.hasOwnProperty(this.id);
|
|
},
|
|
get: function (obj, defaultValue) {
|
|
return obj.hasOwnProperty(this.id) ? obj[this.id] : defaultValue;
|
|
},
|
|
set: function (obj, value) {
|
|
Object.defineProperty(obj, this.id, {
|
|
value: value,
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
}
|
|
};
|
|
this.WeakMap = WeakMap;
|
|
}());
|
|
var Callback = function () {
|
|
function callback() {
|
|
this.queues = {};
|
|
}
|
|
callback.prototype.register = function register(type, callback) {
|
|
var queue = this.queues[type];
|
|
if (queue) {
|
|
if (queue.indexOf(callback) > -1) {
|
|
return;
|
|
}
|
|
} else {
|
|
queue = this.queues[type] = [];
|
|
}
|
|
queue.push(callback);
|
|
};
|
|
callback.prototype.unregister = function unregister(type, callback) {
|
|
var queue = this.queues[type];
|
|
if (!queue) {
|
|
return;
|
|
}
|
|
var i = queue.indexOf(callback);
|
|
if (i !== -1) {
|
|
queue.splice(i, 1);
|
|
}
|
|
if (queue.length === 0) {
|
|
this.queues[type] = null;
|
|
}
|
|
};
|
|
callback.prototype.notify = function notify(type, args) {
|
|
var queue = this.queues[type];
|
|
if (!queue) {
|
|
return;
|
|
}
|
|
queue = queue.slice();
|
|
var args = sliceArguments(arguments, 0);
|
|
for (var i = 0; i < queue.length; i++) {
|
|
if (false) {
|
|
Counter.count('callback(' + type + ').notify');
|
|
}
|
|
var callback = queue[i];
|
|
callback.apply(null, args);
|
|
}
|
|
};
|
|
callback.prototype.notify1 = function notify1(type, value) {
|
|
var queue = this.queues[type];
|
|
if (!queue) {
|
|
return;
|
|
}
|
|
queue = queue.slice();
|
|
for (var i = 0; i < queue.length; i++) {
|
|
if (false) {
|
|
Counter.count('callback(' + type + ').notify1');
|
|
}
|
|
var callback = queue[i];
|
|
callback(type, value);
|
|
}
|
|
};
|
|
return callback;
|
|
}();
|
|
function lazyClass(holder, name, initialize) {
|
|
Object.defineProperty(holder, name, {
|
|
get: function () {
|
|
var start = performance.now();
|
|
var value = initialize();
|
|
print('Initialized Class: ' + name + ' ' + (performance.now() - start).toFixed(4));
|
|
Object.defineProperty(holder, name, {
|
|
value: value,
|
|
writable: true
|
|
});
|
|
return value;
|
|
},
|
|
configurable: true
|
|
});
|
|
}
|
|
var hashBytesTo32BitsAdler = Shumway.HashUtilities.hashBytesTo32BitsAdler;
|
|
var hashBytesTo32BitsMD5 = Shumway.HashUtilities.hashBytesTo32BitsMD5;
|
|
var variableLengthEncodeInt32 = Shumway.StringUtilities.variableLengthEncodeInt32;
|
|
var fromEncoding = Shumway.StringUtilities.fromEncoding;
|
|
var variableLengthDecodeIdentifier = Shumway.StringUtilities.variableLengthDecodeInt32;
|
|
var toEncoding = Shumway.StringUtilities.toEncoding;
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (Options) {
|
|
var Argument = function () {
|
|
function Argument(shortName, longName, type, options) {
|
|
this.shortName = shortName;
|
|
this.longName = longName;
|
|
this.type = type;
|
|
options = options || {};
|
|
this.positional = options.positional;
|
|
this.parseFn = options.parse;
|
|
this.value = options.defaultValue;
|
|
}
|
|
Argument.prototype.parse = function (value) {
|
|
if (this.type === 'boolean') {
|
|
true;
|
|
this.value = value;
|
|
} else if (this.type === 'number') {
|
|
true;
|
|
this.value = parseInt(value, 10);
|
|
} else {
|
|
this.value = value;
|
|
}
|
|
if (this.parseFn) {
|
|
this.parseFn(this.value);
|
|
}
|
|
};
|
|
return Argument;
|
|
}();
|
|
Options.Argument = Argument;
|
|
var ArgumentParser = function () {
|
|
function ArgumentParser() {
|
|
this.args = [];
|
|
}
|
|
ArgumentParser.prototype.addArgument = function (shortName, longName, type, options) {
|
|
var argument = new Argument(shortName, longName, type, options);
|
|
this.args.push(argument);
|
|
return argument;
|
|
};
|
|
ArgumentParser.prototype.addBoundOption = function (option) {
|
|
var options = {
|
|
parse: function (x) {
|
|
option.value = x;
|
|
}
|
|
};
|
|
this.args.push(new Argument(option.shortName, option.longName, option.type, options));
|
|
};
|
|
ArgumentParser.prototype.addBoundOptionSet = function (optionSet) {
|
|
var self = this;
|
|
optionSet.options.forEach(function (x) {
|
|
if (x instanceof OptionSet) {
|
|
self.addBoundOptionSet(x);
|
|
} else {
|
|
true;
|
|
self.addBoundOption(x);
|
|
}
|
|
});
|
|
};
|
|
ArgumentParser.prototype.getUsage = function () {
|
|
var str = '';
|
|
this.args.forEach(function (x) {
|
|
if (!x.positional) {
|
|
str += '[-' + x.shortName + '|--' + x.longName + (x.type === 'boolean' ? '' : ' ' + x.type[0].toUpperCase()) + ']';
|
|
} else {
|
|
str += x.longName;
|
|
}
|
|
str += ' ';
|
|
});
|
|
return str;
|
|
};
|
|
ArgumentParser.prototype.parse = function (args) {
|
|
var nonPositionalArgumentMap = {};
|
|
var positionalArgumentList = [];
|
|
this.args.forEach(function (x) {
|
|
if (x.positional) {
|
|
positionalArgumentList.push(x);
|
|
} else {
|
|
nonPositionalArgumentMap['-' + x.shortName] = x;
|
|
nonPositionalArgumentMap['--' + x.longName] = x;
|
|
}
|
|
});
|
|
var leftoverArguments = [];
|
|
while (args.length) {
|
|
var argString = args.shift();
|
|
var argument = null, value = argString;
|
|
if (argString == '--') {
|
|
leftoverArguments = leftoverArguments.concat(args);
|
|
break;
|
|
} else if (argString.slice(0, 1) == '-' || argString.slice(0, 2) == '--') {
|
|
argument = nonPositionalArgumentMap[argString];
|
|
true;
|
|
if (!argument) {
|
|
continue;
|
|
}
|
|
if (argument.type !== 'boolean') {
|
|
value = args.shift();
|
|
true;
|
|
} else {
|
|
value = true;
|
|
}
|
|
} else if (positionalArgumentList.length) {
|
|
argument = positionalArgumentList.shift();
|
|
} else {
|
|
leftoverArguments.push(value);
|
|
}
|
|
if (argument) {
|
|
argument.parse(value);
|
|
}
|
|
}
|
|
true;
|
|
return leftoverArguments;
|
|
};
|
|
return ArgumentParser;
|
|
}();
|
|
Options.ArgumentParser = ArgumentParser;
|
|
var OptionSet = function () {
|
|
function OptionSet(name) {
|
|
this.name = name;
|
|
this.options = [];
|
|
}
|
|
OptionSet.prototype.register = function (option) {
|
|
this.options.push(option);
|
|
return option;
|
|
};
|
|
OptionSet.prototype.trace = function (writer) {
|
|
writer.enter(this.name + ' {');
|
|
this.options.forEach(function (option) {
|
|
option.trace(writer);
|
|
});
|
|
writer.leave('}');
|
|
};
|
|
return OptionSet;
|
|
}();
|
|
Options.OptionSet = OptionSet;
|
|
var Option = function () {
|
|
function Option(shortName, longName, type, defaultValue, description) {
|
|
this.longName = longName;
|
|
this.shortName = shortName;
|
|
this.type = type;
|
|
this.defaultValue = defaultValue;
|
|
this.value = defaultValue;
|
|
this.description = description;
|
|
}
|
|
Option.prototype.parse = function (value) {
|
|
this.value = value;
|
|
};
|
|
Option.prototype.trace = function (writer) {
|
|
writer.writeLn(('-' + this.shortName + '|--' + this.longName).padRight(' ', 30) + ' = ' + this.type + ' ' + this.value + ' [' + this.defaultValue + ']' + ' (' + this.description + ')');
|
|
};
|
|
return Option;
|
|
}();
|
|
Options.Option = Option;
|
|
}(Shumway.Options || (Shumway.Options = {})));
|
|
var Options = Shumway.Options;
|
|
}(Shumway || (Shumway = {})));
|
|
if (typeof exports !== 'undefined') {
|
|
exports['Shumway'] = Shumway;
|
|
}
|
|
var ArgumentParser = Shumway.Options.ArgumentParser;
|
|
var Option = Shumway.Options.Option;
|
|
var OptionSet = Shumway.Options.OptionSet;
|
|
var ArgumentParser = Shumway.Options.ArgumentParser;
|
|
var Option = Shumway.Options.Option;
|
|
var OptionSet = Shumway.Options.OptionSet;
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (Metrics) {
|
|
var Timer = function () {
|
|
function Timer(parent, name) {
|
|
this._parent = parent;
|
|
this._timers = Shumway.ObjectUtilities.createMap();
|
|
this._name = name;
|
|
this._begin = 0;
|
|
this._last = 0;
|
|
this._total = 0;
|
|
this._count = 0;
|
|
}
|
|
Timer.time = function (name, fn) {
|
|
Timer.start(name);
|
|
fn();
|
|
Timer.stop();
|
|
};
|
|
Timer.start = function (name) {
|
|
Timer._top = Timer._top._timers[name] || (Timer._top._timers[name] = new Timer(Timer._top, name));
|
|
Timer._top.start();
|
|
var tmp = Timer._flat._timers[name] || (Timer._flat._timers[name] = new Timer(Timer._flat, name));
|
|
tmp.start();
|
|
Timer._flatStack.push(tmp);
|
|
};
|
|
Timer.stop = function () {
|
|
Timer._top.stop();
|
|
Timer._top = Timer._top._parent;
|
|
Timer._flatStack.pop().stop();
|
|
};
|
|
Timer.stopStart = function (name) {
|
|
Timer.stop();
|
|
Timer.start(name);
|
|
};
|
|
Timer.prototype.start = function () {
|
|
this._begin = Shumway.getTicks();
|
|
};
|
|
Timer.prototype.stop = function () {
|
|
this._last = Shumway.getTicks() - this._begin;
|
|
this._total += this._last;
|
|
this._count += 1;
|
|
};
|
|
Timer.prototype.toJSON = function () {
|
|
return {
|
|
name: this._name,
|
|
total: this._total,
|
|
timers: this._timers
|
|
};
|
|
};
|
|
Timer.prototype.trace = function (writer) {
|
|
writer.enter(this._name + ': ' + this._total.toFixed(2) + ' ms' + ', count: ' + this._count + ', average: ' + (this._total / this._count).toFixed(2) + ' ms');
|
|
for (var name in this._timers) {
|
|
this._timers[name].trace(writer);
|
|
}
|
|
writer.outdent();
|
|
};
|
|
Timer.trace = function (writer) {
|
|
Timer._base.trace(writer);
|
|
Timer._flat.trace(writer);
|
|
};
|
|
Timer._base = new Timer(null, 'Total');
|
|
Timer._top = Timer._base;
|
|
Timer._flat = new Timer(null, 'Flat');
|
|
Timer._flatStack = [];
|
|
return Timer;
|
|
}();
|
|
Metrics.Timer = Timer;
|
|
var Counter = function () {
|
|
function Counter(enabled) {
|
|
this._enabled = enabled;
|
|
this.clear();
|
|
}
|
|
Counter.prototype.setEnabled = function (enabled) {
|
|
this._enabled = enabled;
|
|
};
|
|
Counter.prototype.clear = function () {
|
|
this._counts = Shumway.ObjectUtilities.createMap();
|
|
};
|
|
Counter.prototype.toJSON = function () {
|
|
return {
|
|
counts: this._counts
|
|
};
|
|
};
|
|
Counter.prototype.count = function (name, increment) {
|
|
if (typeof increment === 'undefined') {
|
|
increment = 1;
|
|
}
|
|
if (!this._enabled) {
|
|
return;
|
|
}
|
|
if (this._counts[name] === undefined) {
|
|
this._counts[name] = 0;
|
|
}
|
|
this._counts[name] += increment;
|
|
return this._counts[name];
|
|
};
|
|
Counter.prototype.trace = function (writer) {
|
|
for (var name in this._counts) {
|
|
writer.writeLn(name + ': ' + this._counts[name]);
|
|
}
|
|
};
|
|
Counter.prototype.traceSorted = function (writer) {
|
|
var pairs = [];
|
|
for (var name in this._counts) {
|
|
pairs.push([
|
|
name,
|
|
this._counts[name]
|
|
]);
|
|
}
|
|
pairs.sort(function (a, b) {
|
|
return b[1] - a[1];
|
|
});
|
|
pairs.forEach(function (pair) {
|
|
writer.writeLn(pair[0] + ': ' + pair[1]);
|
|
});
|
|
};
|
|
return Counter;
|
|
}();
|
|
Metrics.Counter = Counter;
|
|
var Average = function () {
|
|
function Average(max) {
|
|
this._samples = new Float64Array(max);
|
|
this._count = 0;
|
|
this._index = 0;
|
|
}
|
|
Average.prototype.push = function (sample) {
|
|
if (this._count < this._samples.length) {
|
|
this._count++;
|
|
}
|
|
this._index++;
|
|
this._samples[this._index % this._samples.length] = sample;
|
|
};
|
|
Average.prototype.average = function () {
|
|
var sum = 0;
|
|
for (var i = 0; i < this._count; i++) {
|
|
sum += this._samples[i];
|
|
}
|
|
return sum / this._count;
|
|
};
|
|
return Average;
|
|
}();
|
|
Metrics.Average = Average;
|
|
}(Shumway.Metrics || (Shumway.Metrics = {})));
|
|
var Metrics = Shumway.Metrics;
|
|
}(Shumway || (Shumway = {})));
|
|
var Timer = Shumway.Metrics.Timer;
|
|
var Counter = new Shumway.Metrics.Counter(true);
|
|
var Timer = Shumway.Metrics.Timer;
|
|
var Counter = new Shumway.Metrics.Counter(true);
|
|
var FrameCounter = new Shumway.Metrics.Counter(true);
|
|
var systemOptions = new OptionSet('System Options');
|
|
var disassemble = systemOptions.register(new Option('d', 'disassemble', 'boolean', false, 'disassemble'));
|
|
var traceLevel = systemOptions.register(new Option('t', 'traceLevel', 'number', 0, 'trace level'));
|
|
window.print = function (s) {
|
|
console.log(s);
|
|
};
|
|
var CONSTANT_Undefined = 0;
|
|
var CONSTANT_Utf8 = 1;
|
|
var CONSTANT_Float = 2;
|
|
var CONSTANT_Int = 3;
|
|
var CONSTANT_UInt = 4;
|
|
var CONSTANT_PrivateNs = 5;
|
|
var CONSTANT_Double = 6;
|
|
var CONSTANT_QName = 7;
|
|
var CONSTANT_Namespace = 8;
|
|
var CONSTANT_Multiname = 9;
|
|
var CONSTANT_False = 10;
|
|
var CONSTANT_True = 11;
|
|
var CONSTANT_Null = 12;
|
|
var CONSTANT_QNameA = 13;
|
|
var CONSTANT_MultinameA = 14;
|
|
var CONSTANT_RTQName = 15;
|
|
var CONSTANT_RTQNameA = 16;
|
|
var CONSTANT_RTQNameL = 17;
|
|
var CONSTANT_RTQNameLA = 18;
|
|
var CONSTANT_NameL = 19;
|
|
var CONSTANT_NameLA = 20;
|
|
var CONSTANT_NamespaceSet = 21;
|
|
var CONSTANT_PackageNamespace = 22;
|
|
var CONSTANT_PackageInternalNs = 23;
|
|
var CONSTANT_ProtectedNamespace = 24;
|
|
var CONSTANT_ExplicitNamespace = 25;
|
|
var CONSTANT_StaticProtectedNs = 26;
|
|
var CONSTANT_MultinameL = 27;
|
|
var CONSTANT_MultinameLA = 28;
|
|
var CONSTANT_TypeName = 29;
|
|
var CONSTANT_ClassSealed = 1;
|
|
var CONSTANT_ClassFinal = 2;
|
|
var CONSTANT_ClassInterface = 4;
|
|
var CONSTANT_ClassProtectedNs = 8;
|
|
var TRAIT_Slot = 0;
|
|
var TRAIT_Method = 1;
|
|
var TRAIT_Getter = 2;
|
|
var TRAIT_Setter = 3;
|
|
var TRAIT_Class = 4;
|
|
var TRAIT_Function = 5;
|
|
var TRAIT_Const = 6;
|
|
var ATTR_Final = 1;
|
|
var ATTR_Override = 2;
|
|
var ATTR_Metadata = 4;
|
|
var SLOT_var = 0;
|
|
var SLOT_method = 1;
|
|
var SLOT_getter = 2;
|
|
var SLOT_setter = 3;
|
|
var SLOT_class = 4;
|
|
var SLOT_function = 6;
|
|
var METHOD_Arguments = 1;
|
|
var METHOD_Activation = 2;
|
|
var METHOD_Needrest = 4;
|
|
var METHOD_HasOptional = 8;
|
|
var METHOD_IgnoreRest = 16;
|
|
var METHOD_Native = 32;
|
|
var METHOD_Setsdxns = 64;
|
|
var METHOD_HasParamNames = 128;
|
|
var OP_bkpt = 1;
|
|
var OP_nop = 2;
|
|
var OP_throw = 3;
|
|
var OP_getsuper = 4;
|
|
var OP_setsuper = 5;
|
|
var OP_dxns = 6;
|
|
var OP_dxnslate = 7;
|
|
var OP_kill = 8;
|
|
var OP_label = 9;
|
|
var OP_lf32x4 = 10;
|
|
var OP_sf32x4 = 11;
|
|
var OP_ifnlt = 12;
|
|
var OP_ifnle = 13;
|
|
var OP_ifngt = 14;
|
|
var OP_ifnge = 15;
|
|
var OP_jump = 16;
|
|
var OP_iftrue = 17;
|
|
var OP_iffalse = 18;
|
|
var OP_ifeq = 19;
|
|
var OP_ifne = 20;
|
|
var OP_iflt = 21;
|
|
var OP_ifle = 22;
|
|
var OP_ifgt = 23;
|
|
var OP_ifge = 24;
|
|
var OP_ifstricteq = 25;
|
|
var OP_ifstrictne = 26;
|
|
var OP_lookupswitch = 27;
|
|
var OP_pushwith = 28;
|
|
var OP_popscope = 29;
|
|
var OP_nextname = 30;
|
|
var OP_hasnext = 31;
|
|
var OP_pushnull = 32;
|
|
var OP_pushundefined = 33;
|
|
var OP_pushfloat = 34;
|
|
var OP_nextvalue = 35;
|
|
var OP_pushbyte = 36;
|
|
var OP_pushshort = 37;
|
|
var OP_pushtrue = 38;
|
|
var OP_pushfalse = 39;
|
|
var OP_pushnan = 40;
|
|
var OP_pop = 41;
|
|
var OP_dup = 42;
|
|
var OP_swap = 43;
|
|
var OP_pushstring = 44;
|
|
var OP_pushint = 45;
|
|
var OP_pushuint = 46;
|
|
var OP_pushdouble = 47;
|
|
var OP_pushscope = 48;
|
|
var OP_pushnamespace = 49;
|
|
var OP_hasnext2 = 50;
|
|
var OP_li8 = 53;
|
|
var OP_li16 = 54;
|
|
var OP_li32 = 55;
|
|
var OP_lf32 = 56;
|
|
var OP_lf64 = 57;
|
|
var OP_si8 = 58;
|
|
var OP_si16 = 59;
|
|
var OP_si32 = 60;
|
|
var OP_sf32 = 61;
|
|
var OP_sf64 = 62;
|
|
var OP_newfunction = 64;
|
|
var OP_call = 65;
|
|
var OP_construct = 66;
|
|
var OP_callmethod = 67;
|
|
var OP_callstatic = 68;
|
|
var OP_callsuper = 69;
|
|
var OP_callproperty = 70;
|
|
var OP_returnvoid = 71;
|
|
var OP_returnvalue = 72;
|
|
var OP_constructsuper = 73;
|
|
var OP_constructprop = 74;
|
|
var OP_callsuperid = 75;
|
|
var OP_callproplex = 76;
|
|
var OP_callinterface = 77;
|
|
var OP_callsupervoid = 78;
|
|
var OP_callpropvoid = 79;
|
|
var OP_sxi1 = 80;
|
|
var OP_sxi8 = 81;
|
|
var OP_sxi16 = 82;
|
|
var OP_applytype = 83;
|
|
var OP_pushfloat4 = 84;
|
|
var OP_newobject = 85;
|
|
var OP_newarray = 86;
|
|
var OP_newactivation = 87;
|
|
var OP_newclass = 88;
|
|
var OP_getdescendants = 89;
|
|
var OP_newcatch = 90;
|
|
var OP_findpropstrict = 93;
|
|
var OP_findproperty = 94;
|
|
var OP_finddef = 95;
|
|
var OP_getlex = 96;
|
|
var OP_setproperty = 97;
|
|
var OP_getlocal = 98;
|
|
var OP_setlocal = 99;
|
|
var OP_getglobalscope = 100;
|
|
var OP_getscopeobject = 101;
|
|
var OP_getproperty = 102;
|
|
var OP_getouterscope = 103;
|
|
var OP_initproperty = 104;
|
|
var OP_setpropertylate = 105;
|
|
var OP_deleteproperty = 106;
|
|
var OP_deletepropertylate = 107;
|
|
var OP_getslot = 108;
|
|
var OP_setslot = 109;
|
|
var OP_getglobalslot = 110;
|
|
var OP_setglobalslot = 111;
|
|
var OP_convert_s = 112;
|
|
var OP_esc_xelem = 113;
|
|
var OP_esc_xattr = 114;
|
|
var OP_convert_i = 115;
|
|
var OP_convert_u = 116;
|
|
var OP_convert_d = 117;
|
|
var OP_convert_b = 118;
|
|
var OP_convert_o = 119;
|
|
var OP_checkfilter = 120;
|
|
var OP_convert_f = 121;
|
|
var OP_unplus = 122;
|
|
var OP_convert_f4 = 123;
|
|
var OP_coerce = 128;
|
|
var OP_coerce_b = 129;
|
|
var OP_coerce_a = 130;
|
|
var OP_coerce_i = 131;
|
|
var OP_coerce_d = 132;
|
|
var OP_coerce_s = 133;
|
|
var OP_astype = 134;
|
|
var OP_astypelate = 135;
|
|
var OP_coerce_u = 136;
|
|
var OP_coerce_o = 137;
|
|
var OP_negate = 144;
|
|
var OP_increment = 145;
|
|
var OP_inclocal = 146;
|
|
var OP_decrement = 147;
|
|
var OP_declocal = 148;
|
|
var OP_typeof = 149;
|
|
var OP_not = 150;
|
|
var OP_bitnot = 151;
|
|
var OP_add = 160;
|
|
var OP_subtract = 161;
|
|
var OP_multiply = 162;
|
|
var OP_divide = 163;
|
|
var OP_modulo = 164;
|
|
var OP_lshift = 165;
|
|
var OP_rshift = 166;
|
|
var OP_urshift = 167;
|
|
var OP_bitand = 168;
|
|
var OP_bitor = 169;
|
|
var OP_bitxor = 170;
|
|
var OP_equals = 171;
|
|
var OP_strictequals = 172;
|
|
var OP_lessthan = 173;
|
|
var OP_lessequals = 174;
|
|
var OP_greaterthan = 175;
|
|
var OP_greaterequals = 176;
|
|
var OP_instanceof = 177;
|
|
var OP_istype = 178;
|
|
var OP_istypelate = 179;
|
|
var OP_in = 180;
|
|
var OP_increment_i = 192;
|
|
var OP_decrement_i = 193;
|
|
var OP_inclocal_i = 194;
|
|
var OP_declocal_i = 195;
|
|
var OP_negate_i = 196;
|
|
var OP_add_i = 197;
|
|
var OP_subtract_i = 198;
|
|
var OP_multiply_i = 199;
|
|
var OP_getlocal0 = 208;
|
|
var OP_getlocal1 = 209;
|
|
var OP_getlocal2 = 210;
|
|
var OP_getlocal3 = 211;
|
|
var OP_setlocal0 = 212;
|
|
var OP_setlocal1 = 213;
|
|
var OP_setlocal2 = 214;
|
|
var OP_setlocal3 = 215;
|
|
var OP_invalid = 237;
|
|
var OP_debug = 239;
|
|
var OP_debugline = 240;
|
|
var OP_debugfile = 241;
|
|
var OP_bkptline = 242;
|
|
var OP_timestamp = 243;
|
|
var INT_MIN_VALUE = -2147483648;
|
|
var INT_MAX_VALUE = 2147483647;
|
|
var UINT_MIN_VALUE = 0;
|
|
var UINT_MAX_VALUE = 4294967295;
|
|
var SORT_CASEINSENSITIVE = 1;
|
|
var SORT_DESCENDING = 2;
|
|
var SORT_UNIQUESORT = 4;
|
|
var SORT_RETURNINDEXEDARRAY = 8;
|
|
var SORT_NUMERIC = 16;
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
AVM2.Errors = {
|
|
CallOfNonFunctionError: {
|
|
code: 1006,
|
|
message: '%1 is not a function.'
|
|
},
|
|
ConvertNullToObjectError: {
|
|
code: 1009,
|
|
message: 'Cannot access a property or method of a null object reference.'
|
|
},
|
|
ConvertUndefinedToObjectError: {
|
|
code: 1010,
|
|
message: 'A term is undefined and has no properties.'
|
|
},
|
|
ClassNotFoundError: {
|
|
code: 1014,
|
|
message: 'Class %1 could not be found.'
|
|
},
|
|
CheckTypeFailedError: {
|
|
code: 1034,
|
|
message: 'Type Coercion failed: cannot convert %1 to %2.'
|
|
},
|
|
WrongArgumentCountError: {
|
|
code: 1063,
|
|
message: 'Argument count mismatch on %1. Expected %2, got %3.'
|
|
},
|
|
XMLMarkupMustBeWellFormed: {
|
|
code: 1088,
|
|
message: 'The markup in the document following the root element must be well-formed.'
|
|
},
|
|
OutOfRangeError: {
|
|
code: 1125,
|
|
message: 'The index %1 is out of range %2.'
|
|
},
|
|
VectorFixedError: {
|
|
code: 1126,
|
|
message: 'Cannot change the length of a fixed Vector.'
|
|
},
|
|
InvalidParamError: {
|
|
code: 2004,
|
|
message: 'One of the parameters is invalid.'
|
|
},
|
|
ParamRangeError: {
|
|
code: 2006,
|
|
message: 'The supplied index is out of bounds.'
|
|
},
|
|
NullPointerError: {
|
|
code: 2007,
|
|
message: 'Parameter %1 must be non-null.'
|
|
},
|
|
InvalidEnumError: {
|
|
code: 2008,
|
|
message: 'Parameter %1 must be one of the accepted values.'
|
|
},
|
|
ArgumentError: {
|
|
code: 2015,
|
|
message: 'Invalid BitmapData.'
|
|
},
|
|
CompressedDataError: {
|
|
code: 2058,
|
|
message: 'There was an error decompressing the data.'
|
|
},
|
|
SocketConnectError: {
|
|
code: 2011,
|
|
message: 'Socket connection failed to %1:%2.'
|
|
},
|
|
CantAddSelfError: {
|
|
code: 2024,
|
|
message: 'An object cannot be added as a child of itself.'
|
|
},
|
|
NotAChildError: {
|
|
code: 2025,
|
|
message: 'The supplied DisplayObject must be a child of the caller.'
|
|
},
|
|
ExternalInterfaceNotAvailableError: {
|
|
code: 2067,
|
|
message: 'The ExternalInterface is not available in this container. ExternalInterface requires Internet Explorer ActiveX, Firefox, Mozilla 1.7.5 and greater, or other browsers that support NPRuntime.'
|
|
}
|
|
};
|
|
function getErrorMessage(index) {
|
|
if (!Shumway.AVM2.Runtime.debuggerMode.value) {
|
|
return 'Error #' + index;
|
|
}
|
|
for (var k in AVM2.Errors) {
|
|
if (AVM2.Errors[k].code == index) {
|
|
return 'Error #' + index + ': ' + AVM2.Errors[k].message;
|
|
}
|
|
}
|
|
return 'Error #' + index + ': (unknown)';
|
|
}
|
|
AVM2.getErrorMessage = getErrorMessage;
|
|
function formatErrorMessage(error) {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length - 1; _i++) {
|
|
args[_i] = arguments[_i + 1];
|
|
}
|
|
var message = error.message;
|
|
Array.prototype.slice.call(arguments, 1).forEach(function (x, i) {
|
|
message = message.replace('%' + (i + 1), x);
|
|
});
|
|
return 'Error #' + error.code + ': ' + message;
|
|
}
|
|
AVM2.formatErrorMessage = formatErrorMessage;
|
|
function translateErrorMessage(error) {
|
|
if (error.type) {
|
|
switch (error.type) {
|
|
case 'undefined_method':
|
|
return formatErrorMessage(AVM2.Errors.CallOfNonFunctionError, 'value');
|
|
default:
|
|
throw Shumway.Debug.notImplemented(error.type);
|
|
}
|
|
} else {
|
|
if (error.message.indexOf('is not a function') >= 0) {
|
|
return formatErrorMessage(AVM2.Errors.CallOfNonFunctionError, 'value');
|
|
}
|
|
return error.message;
|
|
}
|
|
}
|
|
AVM2.translateErrorMessage = translateErrorMessage;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
var Errors = Shumway.AVM2.Errors;
|
|
var getErrorMessage = Shumway.AVM2.getErrorMessage;
|
|
var formatErrorMessage = Shumway.AVM2.formatErrorMessage;
|
|
var translateErrorMessage = Shumway.AVM2.translateErrorMessage;
|
|
var Errors = Shumway.AVM2.Errors;
|
|
var getErrorMessage = Shumway.AVM2.getErrorMessage;
|
|
var formatErrorMessage = Shumway.AVM2.formatErrorMessage;
|
|
var translateErrorMessage = Shumway.AVM2.translateErrorMessage;
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
AVM2.opcodeTable = [
|
|
null,
|
|
{
|
|
name: 'bkpt',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'nop',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'throw',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'getsuper',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'setsuper',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'dxns',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'dxnslate',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'kill',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'label',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'lf32x4',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'sf32x4',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'ifnlt',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'ifnle',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'ifngt',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'ifnge',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'jump',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'iftrue',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'iffalse',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'ifeq',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'ifne',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'iflt',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'ifle',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'ifgt',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'ifge',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'ifstricteq',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'ifstrictne',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'offset',
|
|
size: 's24',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'lookupswitch',
|
|
canThrow: false,
|
|
operands: null
|
|
},
|
|
{
|
|
name: 'pushwith',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'popscope',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'nextname',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'hasnext',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'pushnull',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'pushundefined',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
null,
|
|
{
|
|
name: 'nextvalue',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'pushbyte',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'value',
|
|
size: 's08',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'pushshort',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'value',
|
|
size: 's16',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'pushtrue',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'pushfalse',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'pushnan',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'pop',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'dup',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'swap',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'pushstring',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'S'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'pushint',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'I'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'pushuint',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'U'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'pushdouble',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'D'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'pushscope',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'pushnamespace',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'N'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'hasnext2',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'object',
|
|
size: 'u30',
|
|
type: ''
|
|
},
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'lix8',
|
|
canThrow: true,
|
|
operands: null
|
|
},
|
|
{
|
|
name: 'lix16',
|
|
canThrow: true,
|
|
operands: null
|
|
},
|
|
{
|
|
name: 'li8',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'li16',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'li32',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'lf32',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'lf64',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'si8',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'si16',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'si32',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'sf32',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'sf64',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
null,
|
|
{
|
|
name: 'newfunction',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'MI'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'call',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'construct',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'callmethod',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
},
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'callstatic',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'MI'
|
|
},
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'callsuper',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
},
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'callproperty',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
},
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'returnvoid',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'returnvalue',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'constructsuper',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'constructprop',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
},
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'callsuperid',
|
|
canThrow: true,
|
|
operands: null
|
|
},
|
|
{
|
|
name: 'callproplex',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
},
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'callinterface',
|
|
canThrow: true,
|
|
operands: null
|
|
},
|
|
{
|
|
name: 'callsupervoid',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
},
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'callpropvoid',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
},
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'sxi1',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'sxi8',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'sxi16',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'applytype',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'pushfloat4',
|
|
canThrow: false,
|
|
operands: null
|
|
},
|
|
{
|
|
name: 'newobject',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'newarray',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'argCount',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'newactivation',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'newclass',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'CI'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'getdescendants',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'newcatch',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'EI'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'findpropglobalstrict',
|
|
canThrow: true,
|
|
operands: null
|
|
},
|
|
{
|
|
name: 'findpropglobal',
|
|
canThrow: true,
|
|
operands: null
|
|
},
|
|
{
|
|
name: 'findpropstrict',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'findproperty',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'finddef',
|
|
canThrow: true,
|
|
operands: null
|
|
},
|
|
{
|
|
name: 'getlex',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'setproperty',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'getlocal',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'setlocal',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'getglobalscope',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'getscopeobject',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'getproperty',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'getouterscope',
|
|
canThrow: false,
|
|
operands: null
|
|
},
|
|
{
|
|
name: 'initproperty',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
null,
|
|
{
|
|
name: 'deleteproperty',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
null,
|
|
{
|
|
name: 'getslot',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'setslot',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'getglobalslot',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'setglobalslot',
|
|
canThrow: false,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'convert_s',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'esc_xelem',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'esc_xattr',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'convert_i',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'convert_u',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'convert_d',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'convert_b',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'convert_o',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'checkfilter',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'convert_f',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'unplus',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'convert_f4',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
{
|
|
name: 'coerce',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'coerce_b',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'coerce_a',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'coerce_i',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'coerce_d',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'coerce_s',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'astype',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'astypelate',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'coerce_u',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'coerce_o',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
{
|
|
name: 'negate',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'increment',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'inclocal',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'decrement',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'declocal',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'typeof',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'not',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'bitnot',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
{
|
|
name: 'add',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'subtract',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'multiply',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'divide',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'modulo',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'lshift',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'rshift',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'urshift',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'bitand',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'bitor',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'bitxor',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'equals',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'strictequals',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'lessthan',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'lessequals',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'greaterthan',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'greaterequals',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'instanceof',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'istype',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'M'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'istypelate',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'in',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
{
|
|
name: 'increment_i',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'decrement_i',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'inclocal_i',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'declocal_i',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'negate_i',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'add_i',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'subtract_i',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'multiply_i',
|
|
canThrow: true,
|
|
operands: []
|
|
},
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
{
|
|
name: 'getlocal0',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'getlocal1',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'getlocal2',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'getlocal3',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'setlocal0',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'setlocal1',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'setlocal2',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
{
|
|
name: 'setlocal3',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
{
|
|
name: 'invalid',
|
|
canThrow: false,
|
|
operands: []
|
|
},
|
|
null,
|
|
{
|
|
name: 'debug',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'debugType',
|
|
size: 'u08',
|
|
type: ''
|
|
},
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'S'
|
|
},
|
|
{
|
|
name: 'reg',
|
|
size: 'u08',
|
|
type: ''
|
|
},
|
|
{
|
|
name: 'extra',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'debugline',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'lineNumber',
|
|
size: 'u30',
|
|
type: ''
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: 'debugfile',
|
|
canThrow: true,
|
|
operands: [
|
|
{
|
|
name: 'index',
|
|
size: 'u30',
|
|
type: 'S'
|
|
}
|
|
]
|
|
},
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
null
|
|
];
|
|
function opcodeName(op) {
|
|
return AVM2.opcodeTable[op].name;
|
|
}
|
|
AVM2.opcodeName = opcodeName;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
var opcodeTable = Shumway.AVM2.opcodeTable;
|
|
var opcodeName = Shumway.AVM2.opcodeName;
|
|
var opcodeTable = Shumway.AVM2.opcodeTable;
|
|
var opcodeName = Shumway.AVM2.opcodeName;
|
|
var __extends = this.__extends || function (d, b) {
|
|
for (var p in b)
|
|
if (b.hasOwnProperty(p))
|
|
d[p] = b[p];
|
|
function __() {
|
|
this.constructor = d;
|
|
}
|
|
__.prototype = b.prototype;
|
|
d.prototype = new __();
|
|
};
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
(function (ABC) {
|
|
var Timer = Shumway.Metrics.Timer;
|
|
var isString = Shumway.isString;
|
|
var isNumber = Shumway.isNumber;
|
|
var isNumeric = Shumway.isNumeric;
|
|
var isObject = Shumway.isObject;
|
|
var textDecoder = null;
|
|
if (typeof TextDecoder !== 'undefined') {
|
|
textDecoder = new TextDecoder();
|
|
}
|
|
var AbcStream = function () {
|
|
function AbcStream(bytes) {
|
|
this._bytes = bytes;
|
|
this._view = new DataView(bytes.buffer, bytes.byteOffset);
|
|
this._position = 0;
|
|
}
|
|
AbcStream._getResultBuffer = function (length) {
|
|
if (!AbcStream._resultBuffer || AbcStream._resultBuffer.length < length) {
|
|
AbcStream._resultBuffer = new Int32Array(length * 2);
|
|
}
|
|
return AbcStream._resultBuffer;
|
|
};
|
|
Object.defineProperty(AbcStream.prototype, 'position', {
|
|
get: function () {
|
|
return this._position;
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
AbcStream.prototype.remaining = function () {
|
|
return this._bytes.length - this._position;
|
|
};
|
|
AbcStream.prototype.seek = function (position) {
|
|
this._position = position;
|
|
};
|
|
AbcStream.prototype.readU8 = function () {
|
|
return this._bytes[this._position++];
|
|
};
|
|
AbcStream.prototype.readU8s = function (count) {
|
|
var b = new Uint8Array(count);
|
|
b.set(this._bytes.subarray(this._position, this._position + count), 0);
|
|
this._position += count;
|
|
return b;
|
|
};
|
|
AbcStream.prototype.readS8 = function () {
|
|
return this._bytes[this._position++] << 24 >> 24;
|
|
};
|
|
AbcStream.prototype.readU32 = function () {
|
|
return this.readS32() >>> 0;
|
|
};
|
|
AbcStream.prototype.readU30 = function () {
|
|
var result = this.readU32();
|
|
if (result & 3221225472) {
|
|
return result;
|
|
}
|
|
return result;
|
|
};
|
|
AbcStream.prototype.readU30Unsafe = function () {
|
|
return this.readU32();
|
|
};
|
|
AbcStream.prototype.readS16 = function () {
|
|
return this.readU30Unsafe() << 16 >> 16;
|
|
};
|
|
AbcStream.prototype.readS32 = function () {
|
|
var result = this.readU8();
|
|
if (result & 128) {
|
|
result = result & 127 | this.readU8() << 7;
|
|
if (result & 16384) {
|
|
result = result & 16383 | this.readU8() << 14;
|
|
if (result & 2097152) {
|
|
result = result & 2097151 | this.readU8() << 21;
|
|
if (result & 268435456) {
|
|
result = result & 268435455 | this.readU8() << 28;
|
|
result = result & 4294967295;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
AbcStream.prototype.readWord = function () {
|
|
var result = this._view.getUint32(this._position, true);
|
|
this._position += 4;
|
|
return result;
|
|
};
|
|
AbcStream.prototype.readS24 = function () {
|
|
var u = this.readU8() | this.readU8() << 8 | this.readU8() << 16;
|
|
return u << 8 >> 8;
|
|
};
|
|
AbcStream.prototype.readDouble = function () {
|
|
var result = this._view.getFloat64(this._position, true);
|
|
this._position += 8;
|
|
return result;
|
|
};
|
|
AbcStream.prototype.readUTFString = function (length) {
|
|
if (textDecoder) {
|
|
var position = this._position;
|
|
this._position += length;
|
|
return textDecoder.decode(this._bytes.subarray(position, position + length));
|
|
}
|
|
var pos = this._position;
|
|
var end = pos + length;
|
|
var bytes = this._bytes;
|
|
var i = 0;
|
|
var result = AbcStream._getResultBuffer(length * 2);
|
|
while (pos < end) {
|
|
var c = bytes[pos++];
|
|
if (c <= 127) {
|
|
result[i++] = c;
|
|
} else if (c >= 192) {
|
|
var code = 0;
|
|
if (c < 224) {
|
|
code = (c & 31) << 6 | bytes[pos++] & 63;
|
|
} else if (c < 240) {
|
|
code = (c & 15) << 12 | (bytes[pos++] & 63) << 6 | bytes[pos++] & 63;
|
|
} else {
|
|
code = ((c & 7) << 18 | (bytes[pos++] & 63) << 12 | (bytes[pos++] & 63) << 6 | bytes[pos++] & 63) - 65536;
|
|
result[i++] = ((code & 1047552) >>> 10) + 55296;
|
|
code = (code & 1023) + 56320;
|
|
}
|
|
result[i++] = code;
|
|
}
|
|
}
|
|
this._position = pos;
|
|
return Shumway.StringUtilities.fromCharCodeArray(result.subarray(0, i));
|
|
};
|
|
AbcStream._resultBuffer = new Int32Array(256);
|
|
return AbcStream;
|
|
}();
|
|
ABC.AbcStream = AbcStream;
|
|
var Parameter = function () {
|
|
function Parameter(name, type, value) {
|
|
this.name = name;
|
|
this.type = type;
|
|
this.value = value;
|
|
}
|
|
return Parameter;
|
|
}();
|
|
ABC.Parameter = Parameter;
|
|
var Trait = function () {
|
|
function Trait(abc, stream, holder) {
|
|
var constantPool = abc.constantPool;
|
|
var methods = abc.methods;
|
|
var classes = abc.classes;
|
|
var metadata = abc.metadata;
|
|
this.holder = holder;
|
|
this.name = constantPool.multinames[stream.readU30()];
|
|
var tag = stream.readU8();
|
|
this.kind = tag & 15;
|
|
this.attributes = tag >> 4 & 15;
|
|
true;
|
|
switch (this.kind) {
|
|
case 0:
|
|
case 6:
|
|
this.slotId = stream.readU30();
|
|
this.typeName = constantPool.multinames[stream.readU30()];
|
|
var valueIndex = stream.readU30();
|
|
this.value = undefined;
|
|
if (valueIndex !== 0) {
|
|
this.hasDefaultValue = true;
|
|
this.value = constantPool.getValue(stream.readU8(), valueIndex);
|
|
}
|
|
break;
|
|
case 1:
|
|
case 3:
|
|
case 2:
|
|
this.dispId = stream.readU30();
|
|
this.methodInfo = methods[stream.readU30()];
|
|
this.methodInfo.name = this.name;
|
|
AbcFile.attachHolder(this.methodInfo, this.holder);
|
|
this.methodInfo.abc = abc;
|
|
break;
|
|
case 4:
|
|
this.slotId = stream.readU30();
|
|
true;
|
|
this.classInfo = classes[stream.readU30()];
|
|
break;
|
|
case 5:
|
|
true;
|
|
break;
|
|
}
|
|
if (this.attributes & 4) {
|
|
var traitMetadata;
|
|
for (var i = 0, j = stream.readU30(); i < j; i++) {
|
|
var md = metadata[stream.readU30()];
|
|
if (md.name === '__go_to_definition_help' || md.name === '__go_to_ctor_definition_help') {
|
|
continue;
|
|
}
|
|
if (!traitMetadata) {
|
|
traitMetadata = {};
|
|
}
|
|
traitMetadata[md.name] = md;
|
|
}
|
|
if (traitMetadata) {
|
|
if (this.isClass()) {
|
|
this.classInfo.metadata = traitMetadata;
|
|
}
|
|
this.metadata = traitMetadata;
|
|
}
|
|
}
|
|
}
|
|
Trait.prototype.isSlot = function () {
|
|
return this.kind === 0;
|
|
};
|
|
Trait.prototype.isConst = function () {
|
|
return this.kind === 6;
|
|
};
|
|
Trait.prototype.isMethod = function () {
|
|
return this.kind === 1;
|
|
};
|
|
Trait.prototype.isClass = function () {
|
|
return this.kind === 4;
|
|
};
|
|
Trait.prototype.isGetter = function () {
|
|
return this.kind === 2;
|
|
};
|
|
Trait.prototype.isSetter = function () {
|
|
return this.kind === 3;
|
|
};
|
|
Trait.prototype.isProtected = function () {
|
|
true;
|
|
return this.name.namespaces[0].isProtected();
|
|
};
|
|
Trait.prototype.kindName = function () {
|
|
switch (this.kind) {
|
|
case 0:
|
|
return 'Slot';
|
|
case 6:
|
|
return 'Const';
|
|
case 1:
|
|
return 'Method';
|
|
case 3:
|
|
return 'Setter';
|
|
case 2:
|
|
return 'Getter';
|
|
case 4:
|
|
return 'Class';
|
|
case 5:
|
|
return 'Function';
|
|
}
|
|
Shumway.Debug.unexpected();
|
|
};
|
|
Trait.prototype.isOverride = function () {
|
|
return this.attributes & 2;
|
|
};
|
|
Trait.prototype.isFinal = function () {
|
|
return this.attributes & 1;
|
|
};
|
|
Trait.prototype.toString = function () {
|
|
var str = Shumway.IntegerUtilities.getFlags(this.attributes, 'final|override|metadata'.split('|'));
|
|
if (str) {
|
|
str += ' ';
|
|
}
|
|
str += Multiname.getQualifiedName(this.name);
|
|
switch (this.kind) {
|
|
case 0:
|
|
case 6:
|
|
return str + ', typeName: ' + this.typeName + ', slotId: ' + this.slotId + ', value: ' + this.value;
|
|
case 1:
|
|
case 3:
|
|
case 2:
|
|
return str + ', ' + this.kindName() + ': ' + this.methodInfo.name;
|
|
case 4:
|
|
return str + ', slotId: ' + this.slotId + ', class: ' + this.classInfo;
|
|
case 5:
|
|
break;
|
|
}
|
|
};
|
|
Trait.parseTraits = function (abc, stream, holder) {
|
|
var count = stream.readU30();
|
|
var traits = [];
|
|
for (var i = 0; i < count; i++) {
|
|
traits.push(new Trait(abc, stream, holder));
|
|
}
|
|
return traits;
|
|
};
|
|
return Trait;
|
|
}();
|
|
ABC.Trait = Trait;
|
|
var Info = function () {
|
|
function Info(abc, index) {
|
|
this.abc = abc;
|
|
this.index = index;
|
|
}
|
|
return Info;
|
|
}();
|
|
ABC.Info = Info;
|
|
var MethodInfo = function (_super) {
|
|
__extends(MethodInfo, _super);
|
|
function MethodInfo(abc, index, stream) {
|
|
_super.call(this, abc, index);
|
|
var constantPool = abc.constantPool;
|
|
var parameterCount = stream.readU30();
|
|
this.returnType = constantPool.multinames[stream.readU30()];
|
|
this.parameters = [];
|
|
for (var i = 0; i < parameterCount; i++) {
|
|
this.parameters.push(new Parameter(undefined, constantPool.multinames[stream.readU30()], undefined));
|
|
}
|
|
this.debugName = constantPool.strings[stream.readU30()];
|
|
this.flags = stream.readU8();
|
|
var optionalCount = 0;
|
|
if (this.flags & 8) {
|
|
optionalCount = stream.readU30();
|
|
true;
|
|
for (var i = parameterCount - optionalCount; i < parameterCount; i++) {
|
|
var valueIndex = stream.readU30();
|
|
this.parameters[i].value = constantPool.getValue(stream.readU8(), valueIndex);
|
|
}
|
|
}
|
|
if (this.flags & 128) {
|
|
for (var i = 0; i < parameterCount; i++) {
|
|
if (false) {
|
|
this.parameters[i].name = constantPool.strings[stream.readU30()];
|
|
} else {
|
|
stream.readU30();
|
|
this.parameters[i].name = MethodInfo._getParameterName(i);
|
|
}
|
|
}
|
|
} else {
|
|
for (var i = 0; i < parameterCount; i++) {
|
|
this.parameters[i].name = MethodInfo._getParameterName(i);
|
|
}
|
|
}
|
|
}
|
|
MethodInfo._getParameterName = function (i) {
|
|
true;
|
|
return String.fromCharCode('A'.charCodeAt(0) + i);
|
|
};
|
|
MethodInfo.prototype.toString = function () {
|
|
var flags = Shumway.IntegerUtilities.getFlags(this.flags, 'NEED_ARGUMENTS|NEED_ACTIVATION|NEED_REST|HAS_OPTIONAL|||SET_DXN|HAS_PARAM_NAMES'.split('|'));
|
|
return (flags ? flags + ' ' : '') + this.name;
|
|
};
|
|
MethodInfo.prototype.hasOptional = function () {
|
|
return !(!(this.flags & 8));
|
|
};
|
|
MethodInfo.prototype.needsActivation = function () {
|
|
return !(!(this.flags & 2));
|
|
};
|
|
MethodInfo.prototype.needsRest = function () {
|
|
return !(!(this.flags & 4));
|
|
};
|
|
MethodInfo.prototype.needsArguments = function () {
|
|
return !(!(this.flags & 1));
|
|
};
|
|
MethodInfo.prototype.isNative = function () {
|
|
return !(!(this.flags & 32));
|
|
};
|
|
MethodInfo.prototype.isClassMember = function () {
|
|
return this.holder instanceof ClassInfo;
|
|
};
|
|
MethodInfo.prototype.isInstanceMember = function () {
|
|
return this.holder instanceof InstanceInfo;
|
|
};
|
|
MethodInfo.prototype.isScriptMember = function () {
|
|
return this.holder instanceof ScriptInfo;
|
|
};
|
|
MethodInfo.parseException = function (abc, stream) {
|
|
var multinames = abc.constantPool.multinames;
|
|
var ex = {
|
|
start: stream.readU30(),
|
|
end: stream.readU30(),
|
|
target: stream.readU30(),
|
|
typeName: multinames[stream.readU30()],
|
|
varName: multinames[stream.readU30()]
|
|
};
|
|
true;
|
|
true;
|
|
return ex;
|
|
};
|
|
MethodInfo.parseBody = function (abc, stream) {
|
|
var constantPool = abc.constantPool;
|
|
var methods = abc.methods;
|
|
var index = stream.readU30();
|
|
var mi = methods[index];
|
|
mi.index = index;
|
|
mi.hasBody = true;
|
|
mi.hash = abc.hash + 196608 + index;
|
|
true;
|
|
mi.maxStack = stream.readU30();
|
|
mi.localCount = stream.readU30();
|
|
mi.initScopeDepth = stream.readU30();
|
|
mi.maxScopeDepth = stream.readU30();
|
|
mi.code = stream.readU8s(stream.readU30());
|
|
var exceptions = [];
|
|
var exceptionCount = stream.readU30();
|
|
for (var i = 0; i < exceptionCount; ++i) {
|
|
exceptions.push(MethodInfo.parseException(abc, stream));
|
|
}
|
|
mi.exceptions = exceptions;
|
|
mi.traits = Trait.parseTraits(abc, stream, mi);
|
|
};
|
|
MethodInfo.prototype.hasExceptions = function () {
|
|
return this.exceptions.length > 0;
|
|
};
|
|
return MethodInfo;
|
|
}(Info);
|
|
ABC.MethodInfo = MethodInfo;
|
|
var InstanceInfo = function (_super) {
|
|
__extends(InstanceInfo, _super);
|
|
function InstanceInfo(abc, index, stream) {
|
|
_super.call(this, abc, index);
|
|
this.runtimeId = InstanceInfo.nextID++;
|
|
var constantPool = abc.constantPool;
|
|
var methods = abc.methods;
|
|
this.name = constantPool.multinames[stream.readU30()];
|
|
true;
|
|
this.superName = constantPool.multinames[stream.readU30()];
|
|
this.flags = stream.readU8();
|
|
this.protectedNs = undefined;
|
|
if (this.flags & 8) {
|
|
this.protectedNs = constantPool.namespaces[stream.readU30()];
|
|
}
|
|
var interfaceCount = stream.readU30();
|
|
this.interfaces = [];
|
|
for (var i = 0; i < interfaceCount; i++) {
|
|
this.interfaces[i] = constantPool.multinames[stream.readU30()];
|
|
}
|
|
this.init = methods[stream.readU30()];
|
|
this.init.isInstanceInitializer = true;
|
|
this.init.name = this.name;
|
|
AbcFile.attachHolder(this.init, this);
|
|
this.traits = Trait.parseTraits(abc, stream, this);
|
|
}
|
|
InstanceInfo.prototype.toString = function () {
|
|
var flags = Shumway.IntegerUtilities.getFlags(this.flags & 8, 'sealed|final|interface|protected'.split('|'));
|
|
var str = (flags ? flags + ' ' : '') + this.name;
|
|
if (this.superName) {
|
|
str += ' extends ' + this.superName;
|
|
}
|
|
return str;
|
|
};
|
|
InstanceInfo.prototype.isFinal = function () {
|
|
return !(!(this.flags & 2));
|
|
};
|
|
InstanceInfo.prototype.isSealed = function () {
|
|
return !(!(this.flags & 1));
|
|
};
|
|
InstanceInfo.prototype.isInterface = function () {
|
|
return !(!(this.flags & 4));
|
|
};
|
|
InstanceInfo.nextID = 1;
|
|
return InstanceInfo;
|
|
}(Info);
|
|
ABC.InstanceInfo = InstanceInfo;
|
|
var ClassInfo = function (_super) {
|
|
__extends(ClassInfo, _super);
|
|
function ClassInfo(abc, index, stream) {
|
|
_super.call(this, abc, index);
|
|
this.runtimeId = ClassInfo.nextID++;
|
|
this.abc = abc;
|
|
this.hash = abc.hash + 65536 + index;
|
|
this.index = index;
|
|
this.init = abc.methods[stream.readU30()];
|
|
this.init.isClassInitializer = true;
|
|
AbcFile.attachHolder(this.init, this);
|
|
this.traits = Trait.parseTraits(abc, stream, this);
|
|
this.instanceInfo = abc.instances[index];
|
|
this.instanceInfo.classInfo = this;
|
|
this.defaultValue = ClassInfo._getDefaultValue(this.instanceInfo.name);
|
|
}
|
|
ClassInfo._getDefaultValue = function (qn) {
|
|
if (Multiname.getQualifiedName(qn) === Multiname.Int || Multiname.getQualifiedName(qn) === Multiname.Uint) {
|
|
return 0;
|
|
} else if (Multiname.getQualifiedName(qn) === Multiname.Number) {
|
|
return NaN;
|
|
} else if (Multiname.getQualifiedName(qn) === Multiname.Boolean) {
|
|
return false;
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
ClassInfo.prototype.toString = function () {
|
|
return this.instanceInfo.name.toString();
|
|
};
|
|
ClassInfo.nextID = 1;
|
|
return ClassInfo;
|
|
}(Info);
|
|
ABC.ClassInfo = ClassInfo;
|
|
var ScriptInfo = function (_super) {
|
|
__extends(ScriptInfo, _super);
|
|
function ScriptInfo(abc, index, stream) {
|
|
_super.call(this, abc, index);
|
|
this.runtimeId = ClassInfo.nextID++;
|
|
this.hash = abc.hash + 131072 + index;
|
|
this.name = abc.name + '$script' + index;
|
|
this.init = abc.methods[stream.readU30()];
|
|
this.init.isScriptInitializer = true;
|
|
AbcFile.attachHolder(this.init, this);
|
|
this.traits = Trait.parseTraits(abc, stream, this);
|
|
}
|
|
Object.defineProperty(ScriptInfo.prototype, 'entryPoint', {
|
|
get: function () {
|
|
return this.init;
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
ScriptInfo.prototype.toString = function () {
|
|
return this.name;
|
|
};
|
|
ScriptInfo.nextID = 1;
|
|
return ScriptInfo;
|
|
}(Info);
|
|
ABC.ScriptInfo = ScriptInfo;
|
|
var AbcFile = function () {
|
|
function AbcFile(bytes, name, hash) {
|
|
if (typeof hash === 'undefined') {
|
|
hash = 0;
|
|
}
|
|
Timer.start('Parse ABC');
|
|
this.name = name;
|
|
this.env = {};
|
|
var computedHash;
|
|
if (!hash || !true) {
|
|
Timer.start('Adler');
|
|
computedHash = Shumway.HashUtilities.hashBytesTo32BitsAdler(bytes, 0, bytes.length);
|
|
Timer.stop();
|
|
}
|
|
if (hash) {
|
|
this.hash = hash;
|
|
true;
|
|
} else {
|
|
this.hash = computedHash;
|
|
}
|
|
var n, i;
|
|
var stream = new AbcStream(bytes);
|
|
AbcFile._checkMagic(stream);
|
|
Timer.start('Parse constantPool');
|
|
this.constantPool = new ConstantPool(stream, this);
|
|
Timer.stop();
|
|
Timer.start('Parse Method Infos');
|
|
this.methods = [];
|
|
n = stream.readU30();
|
|
for (i = 0; i < n; ++i) {
|
|
this.methods.push(new MethodInfo(this, i, stream));
|
|
}
|
|
Timer.stop();
|
|
Timer.start('Parse MetaData Infos');
|
|
this.metadata = [];
|
|
n = stream.readU30();
|
|
for (i = 0; i < n; ++i) {
|
|
this.metadata.push(new MetaDataInfo(this, stream));
|
|
}
|
|
Timer.stop();
|
|
Timer.start('Parse Instance Infos');
|
|
this.instances = [];
|
|
n = stream.readU30();
|
|
for (i = 0; i < n; ++i) {
|
|
this.instances.push(new InstanceInfo(this, i, stream));
|
|
}
|
|
Timer.stop();
|
|
Timer.start('Parse Class Infos');
|
|
this.classes = [];
|
|
for (i = 0; i < n; ++i) {
|
|
this.classes.push(new ClassInfo(this, i, stream));
|
|
}
|
|
Timer.stop();
|
|
Timer.start('Parse Script Infos');
|
|
this.scripts = [];
|
|
n = stream.readU30();
|
|
for (i = 0; i < n; ++i) {
|
|
this.scripts.push(new ScriptInfo(this, i, stream));
|
|
}
|
|
Timer.stop();
|
|
Timer.start('Parse Method Body Info');
|
|
n = stream.readU30();
|
|
for (i = 0; i < n; ++i) {
|
|
MethodInfo.parseBody(this, stream);
|
|
}
|
|
Timer.stop();
|
|
Timer.stop();
|
|
}
|
|
AbcFile._checkMagic = function (stream) {
|
|
var magic = stream.readWord();
|
|
var flashPlayerBrannan = 46 << 16 | 15;
|
|
if (magic < flashPlayerBrannan) {
|
|
throw new Error('Invalid ABC File (magic = ' + Number(magic).toString(16) + ')');
|
|
}
|
|
};
|
|
Object.defineProperty(AbcFile.prototype, 'lastScript', {
|
|
get: function () {
|
|
true;
|
|
return this.scripts[this.scripts.length - 1];
|
|
},
|
|
enumerable: true,
|
|
configurable: true
|
|
});
|
|
AbcFile.attachHolder = function (mi, holder) {
|
|
true;
|
|
mi.holder = holder;
|
|
};
|
|
AbcFile.prototype.toString = function () {
|
|
return this.name;
|
|
};
|
|
return AbcFile;
|
|
}();
|
|
ABC.AbcFile = AbcFile;
|
|
var Namespace = function () {
|
|
function Namespace(kind, uri, prefix, uniqueURIHash) {
|
|
if (typeof uri === 'undefined') {
|
|
uri = '';
|
|
}
|
|
if (uri === undefined) {
|
|
uri = '';
|
|
}
|
|
if (prefix !== undefined) {
|
|
this.prefix = prefix;
|
|
}
|
|
this.kind = kind;
|
|
this.uri = uri;
|
|
this._buildNamespace(uniqueURIHash);
|
|
}
|
|
Namespace.prototype._buildNamespace = function (uniqueURIHash) {
|
|
if (this.kind === 22) {
|
|
this.kind = 8;
|
|
}
|
|
if (this.isPublic() && this.uri) {
|
|
var n = this.uri.length - 1;
|
|
var mark = this.uri.charCodeAt(n);
|
|
if (mark > Namespace._MIN_API_MARK) {
|
|
this.uri = this.uri.substring(0, n - 1);
|
|
}
|
|
} else if (this.isUnique()) {
|
|
this.uri = 'private ' + uniqueURIHash;
|
|
}
|
|
this.qualifiedName = Namespace._qualifyNamespace(this.kind, this.uri, this.prefix ? this.prefix : '');
|
|
};
|
|
Namespace._hashNamespace = function (kind, uri, prefix) {
|
|
var data = new Int32Array(1 + uri.length + prefix.length);
|
|
var j = 0;
|
|
data[j++] = kind;
|
|
var index = Namespace._knownURIs.indexOf(uri);
|
|
if (index >= 0) {
|
|
return kind << 2 | index;
|
|
} else {
|
|
for (var i = 0; i < uri.length; i++) {
|
|
data[j++] = uri.charCodeAt(i);
|
|
}
|
|
}
|
|
for (var i = 0; i < prefix.length; i++) {
|
|
data[j++] = prefix.charCodeAt(i);
|
|
}
|
|
return Shumway.HashUtilities.hashBytesTo32BitsMD5(data, 0, j);
|
|
};
|
|
Namespace._qualifyNamespace = function (kind, uri, prefix) {
|
|
var key = kind + uri;
|
|
var mangledNamespace = Namespace._mangledNamespaceCache[key];
|
|
if (mangledNamespace) {
|
|
return mangledNamespace;
|
|
}
|
|
mangledNamespace = Shumway.StringUtilities.variableLengthEncodeInt32(Namespace._hashNamespace(kind, uri, prefix));
|
|
Namespace._mangledNamespaceMap[mangledNamespace] = {
|
|
kind: kind,
|
|
uri: uri,
|
|
prefix: prefix
|
|
};
|
|
Namespace._mangledNamespaceCache[key] = mangledNamespace;
|
|
return mangledNamespace;
|
|
};
|
|
Namespace.fromQualifiedName = function (qn) {
|
|
var length = Shumway.StringUtilities.fromEncoding(qn[0]);
|
|
var mangledNamespace = qn.substring(0, length + 1);
|
|
var ns = Namespace._mangledNamespaceMap[mangledNamespace];
|
|
return new Namespace(ns.kind, ns.uri, ns.prefix);
|
|
};
|
|
Namespace.kindFromString = function (str) {
|
|
for (var kind in Namespace._kinds) {
|
|
if (Namespace._kinds[kind] === str) {
|
|
return kind;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
Namespace.createNamespace = function (uri, prefix) {
|
|
return new Namespace(8, uri, prefix);
|
|
};
|
|
Namespace.parse = function (constantPool, stream, hash) {
|
|
var kind = stream.readU8();
|
|
var uri = constantPool.strings[stream.readU30()];
|
|
return new Namespace(kind, uri, undefined, hash);
|
|
};
|
|
Namespace.prototype.isPublic = function () {
|
|
return this.kind === 8 || this.kind === 22;
|
|
};
|
|
Namespace.prototype.isProtected = function () {
|
|
return this.kind === 24;
|
|
};
|
|
Namespace.prototype.isUnique = function () {
|
|
return this.kind === 5 && !this.uri;
|
|
};
|
|
Namespace.prototype.isDynamic = function () {
|
|
return this.isPublic() && !this.uri;
|
|
};
|
|
Namespace.prototype.getURI = function () {
|
|
return this.uri;
|
|
};
|
|
Namespace.prototype.toString = function () {
|
|
return Namespace._kinds[this.kind] + (this.uri ? ' ' + this.uri : '');
|
|
};
|
|
Namespace.prototype.clone = function () {
|
|
var ns = Object.create(Namespace.prototype);
|
|
ns.kind = this.kind;
|
|
ns.uri = this.uri;
|
|
ns.prefix = this.prefix;
|
|
ns.qualifiedName = this.qualifiedName;
|
|
return ns;
|
|
};
|
|
Namespace.prototype.isEqualTo = function (other) {
|
|
return this.qualifiedName === other.qualifiedName;
|
|
};
|
|
Namespace.prototype.inNamespaceSet = function (set) {
|
|
for (var i = 0; i < set.length; i++) {
|
|
if (set[i].qualifiedName === this.qualifiedName) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
Namespace.prototype.getAccessModifier = function () {
|
|
return Namespace._kinds[this.kind];
|
|
};
|
|
Namespace.prototype.getQualifiedName = function () {
|
|
return this.qualifiedName;
|
|
};
|
|
Namespace.fromSimpleName = function (simpleName) {
|
|
if (simpleName in Namespace._simpleNameCache) {
|
|
return Namespace._simpleNameCache[simpleName];
|
|
}
|
|
var namespaceNames;
|
|
if (simpleName.indexOf('[') === 0) {
|
|
true;
|
|
namespaceNames = simpleName.substring(1, simpleName.length - 1).split(',');
|
|
} else {
|
|
namespaceNames = [
|
|
simpleName
|
|
];
|
|
}
|
|
return Namespace._simpleNameCache[simpleName] = namespaceNames.map(function (name) {
|
|
name = name.trim();
|
|
var kindName, uri;
|
|
if (name.indexOf(' ') > 0) {
|
|
kindName = name.substring(0, name.indexOf(' ')).trim();
|
|
uri = name.substring(name.indexOf(' ') + 1).trim();
|
|
} else {
|
|
var kinds = Namespace._kinds;
|
|
if (name === kinds[8] || name === kinds[23] || name === kinds[5] || name === kinds[24] || name === kinds[25] || name === kinds[26]) {
|
|
kindName = name;
|
|
uri = '';
|
|
} else {
|
|
kindName = Namespace._publicPrefix;
|
|
uri = name;
|
|
}
|
|
}
|
|
return new Namespace(Namespace.kindFromString(kindName), uri);
|
|
});
|
|
};
|
|
Namespace._publicPrefix = 'public';
|
|
Namespace._kinds = function () {
|
|
var map = Shumway.ObjectUtilities.createMap();
|
|
map[8] = Namespace._publicPrefix;
|
|
map[23] = 'packageInternal';
|
|
map[5] = 'private';
|
|
map[24] = 'protected';
|
|
map[25] = 'explicit';
|
|
map[26] = 'staticProtected';
|
|
return map;
|
|
}();
|
|
Namespace._MIN_API_MARK = 58004;
|
|
Namespace._MAX_API_MARK = 63743;
|
|
Namespace._knownURIs = [
|
|
''
|
|
];
|
|
Namespace._mangledNamespaceCache = Shumway.ObjectUtilities.createMap();
|
|
Namespace._mangledNamespaceMap = Shumway.ObjectUtilities.createMap();
|
|
Namespace.PUBLIC = new Namespace(8);
|
|
Namespace.PROTECTED = new Namespace(24);
|
|
Namespace.PROXY = new Namespace(8, 'http://www.adobe.com/2006/actionscript/flash/proxy');
|
|
Namespace._simpleNameCache = Shumway.ObjectUtilities.createMap();
|
|
return Namespace;
|
|
}();
|
|
ABC.Namespace = Namespace;
|
|
var Multiname = function () {
|
|
function Multiname(namespaces, name, flags) {
|
|
if (typeof flags === 'undefined') {
|
|
flags = 0;
|
|
}
|
|
if (name !== undefined) {
|
|
true;
|
|
}
|
|
this.runtimeId = Multiname._nextID++;
|
|
this.namespaces = namespaces;
|
|
this.name = name;
|
|
this.flags = flags;
|
|
}
|
|
Multiname.parse = function (constantPool, stream, multinames, patchFactoryTypes) {
|
|
var index = 0;
|
|
var kind = stream.readU8();
|
|
var name, namespaces = [], flags = 0;
|
|
switch (kind) {
|
|
case 7:
|
|
case 13:
|
|
index = stream.readU30();
|
|
if (index) {
|
|
namespaces = [
|
|
constantPool.namespaces[index]
|
|
];
|
|
} else {
|
|
flags &= ~Multiname.RUNTIME_NAME;
|
|
}
|
|
index = stream.readU30();
|
|
if (index) {
|
|
name = constantPool.strings[index];
|
|
}
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
index = stream.readU30();
|
|
if (index) {
|
|
name = constantPool.strings[index];
|
|
} else {
|
|
flags &= ~Multiname.RUNTIME_NAME;
|
|
}
|
|
flags |= Multiname.RUNTIME_NAMESPACE;
|
|
break;
|
|
case 17:
|
|
case 18:
|
|
flags |= Multiname.RUNTIME_NAMESPACE;
|
|
flags |= Multiname.RUNTIME_NAME;
|
|
break;
|
|
case 9:
|
|
case 14:
|
|
index = stream.readU30();
|
|
if (index) {
|
|
name = constantPool.strings[index];
|
|
} else {
|
|
flags &= ~Multiname.RUNTIME_NAME;
|
|
}
|
|
index = stream.readU30();
|
|
true;
|
|
namespaces = constantPool.namespaceSets[index];
|
|
break;
|
|
case 27:
|
|
case 28:
|
|
flags |= Multiname.RUNTIME_NAME;
|
|
index = stream.readU30();
|
|
true;
|
|
namespaces = constantPool.namespaceSets[index];
|
|
break;
|
|
case 29:
|
|
var factoryTypeIndex = stream.readU32();
|
|
if (multinames[factoryTypeIndex]) {
|
|
namespaces = multinames[factoryTypeIndex].namespaces;
|
|
name = multinames[factoryTypeIndex].name;
|
|
}
|
|
var typeParameterCount = stream.readU32();
|
|
true;
|
|
var typeParameterIndex = stream.readU32();
|
|
true;
|
|
var mn = new Multiname(namespaces, name, flags);
|
|
mn.typeParameter = multinames[typeParameterIndex];
|
|
if (!multinames[factoryTypeIndex]) {
|
|
patchFactoryTypes.push({
|
|
multiname: mn,
|
|
index: factoryTypeIndex
|
|
});
|
|
}
|
|
return mn;
|
|
default:
|
|
Shumway.Debug.unexpected();
|
|
break;
|
|
}
|
|
switch (kind) {
|
|
case 13:
|
|
case 16:
|
|
case 18:
|
|
case 14:
|
|
case 28:
|
|
flags |= Multiname.ATTRIBUTE;
|
|
break;
|
|
}
|
|
return new Multiname(namespaces, name, flags);
|
|
};
|
|
Multiname.isMultiname = function (mn) {
|
|
return typeof mn === 'number' || typeof mn === 'string' || mn instanceof Multiname || mn instanceof Number;
|
|
};
|
|
Multiname.needsResolution = function (mn) {
|
|
return mn instanceof Multiname && mn.namespaces.length > 1;
|
|
};
|
|
Multiname.isQName = function (mn) {
|
|
if (mn instanceof Multiname) {
|
|
return mn.namespaces && mn.namespaces.length === 1;
|
|
}
|
|
return true;
|
|
};
|
|
Multiname.isRuntimeName = function (mn) {
|
|
return mn instanceof Multiname && mn.isRuntimeName();
|
|
};
|
|
Multiname.isRuntimeNamespace = function (mn) {
|
|
return mn instanceof Multiname && mn.isRuntimeNamespace();
|
|
};
|
|
Multiname.isRuntime = function (mn) {
|
|
return mn instanceof Multiname && mn.isRuntimeName() || mn.isRuntimeNamespace();
|
|
};
|
|
Multiname.getQualifiedName = function (mn) {
|
|
true;
|
|
if (mn instanceof Multiname) {
|
|
if (mn.qualifiedName !== undefined) {
|
|
return mn.qualifiedName;
|
|
}
|
|
var name = String(mn.name);
|
|
if (isNumeric(name) && mn.namespaces[0].isPublic()) {
|
|
return mn.qualifiedName = name;
|
|
}
|
|
mn = mn.qualifiedName = Multiname.qualifyName(mn.namespaces[0], name);
|
|
}
|
|
return mn;
|
|
};
|
|
Multiname.qualifyName = function (namespace, name) {
|
|
return '$' + namespace.qualifiedName + name;
|
|
};
|
|
Multiname.stripPublicQualifier = function (qn) {
|
|
var publicQualifier = '$' + Namespace.PUBLIC.qualifiedName;
|
|
var index = qn.indexOf(publicQualifier);
|
|
if (index !== 0) {
|
|
return undefined;
|
|
}
|
|
return qn.substring(publicQualifier.length);
|
|
};
|
|
Multiname.fromQualifiedName = function (qn) {
|
|
if (qn instanceof Multiname) {
|
|
return qn;
|
|
}
|
|
if (isNumeric(qn)) {
|
|
return new Multiname([
|
|
Namespace.PUBLIC
|
|
], qn);
|
|
}
|
|
if (qn[0] !== '$') {
|
|
return;
|
|
}
|
|
var ns = Namespace.fromQualifiedName(qn.substring(1));
|
|
return new Multiname([
|
|
ns
|
|
], qn.substring(1 + ns.qualifiedName.length));
|
|
};
|
|
Multiname.getNameFromPublicQualifiedName = function (qn) {
|
|
var mn = Multiname.fromQualifiedName(qn);
|
|
true;
|
|
return mn.name;
|
|
};
|
|
Multiname.getFullQualifiedName = function (mn) {
|
|
var qn = Multiname.getQualifiedName(mn);
|
|
if (mn instanceof Multiname && mn.typeParameter) {
|
|
qn += '$' + Multiname.getFullQualifiedName(mn.typeParameter);
|
|
}
|
|
return qn;
|
|
};
|
|
Multiname.getPublicQualifiedName = function (name) {
|
|
if (isNumeric(name)) {
|
|
return Shumway.toNumber(name);
|
|
} else if (name !== null && isObject(name)) {
|
|
return name;
|
|
}
|
|
return Multiname.qualifyName(Namespace.PUBLIC, name);
|
|
};
|
|
Multiname.isPublicQualifiedName = function (qn) {
|
|
return typeof qn === 'number' || isNumeric(qn) || qn.indexOf(Namespace.PUBLIC.qualifiedName) === 1;
|
|
};
|
|
Multiname.getAccessModifier = function (mn) {
|
|
true;
|
|
if (typeof mn === 'number' || typeof mn === 'string' || mn instanceof Number) {
|
|
return 'public';
|
|
}
|
|
true;
|
|
return mn.namespaces[0].getAccessModifier();
|
|
};
|
|
Multiname.isNumeric = function (mn) {
|
|
if (typeof mn === 'number') {
|
|
return true;
|
|
} else if (typeof mn === 'string') {
|
|
return isNumeric(mn);
|
|
}
|
|
return !isNaN(parseInt(Multiname.getName(mn), 10));
|
|
};
|
|
Multiname.getName = function (mn) {
|
|
true;
|
|
true;
|
|
return mn.getName();
|
|
};
|
|
Multiname.isAnyName = function (mn) {
|
|
return typeof mn === 'object' && !mn.isRuntimeName() && !mn.name;
|
|
};
|
|
Multiname.fromSimpleName = function (simpleName) {
|
|
true;
|
|
if (simpleName in Multiname._simpleNameCache) {
|
|
return Multiname._simpleNameCache[simpleName];
|
|
}
|
|
var nameIndex, namespaceIndex, name, namespace;
|
|
nameIndex = simpleName.lastIndexOf('.');
|
|
if (nameIndex <= 0) {
|
|
nameIndex = simpleName.lastIndexOf(' ');
|
|
}
|
|
if (nameIndex > 0 && nameIndex < simpleName.length - 1) {
|
|
name = simpleName.substring(nameIndex + 1).trim();
|
|
namespace = simpleName.substring(0, nameIndex).trim();
|
|
} else {
|
|
name = simpleName;
|
|
namespace = '';
|
|
}
|
|
return Multiname._simpleNameCache[simpleName] = new Multiname(Namespace.fromSimpleName(namespace), name);
|
|
};
|
|
Multiname.prototype.getQName = function (index) {
|
|
true;
|
|
if (!this._qualifiedNameCache) {
|
|
this._qualifiedNameCache = Shumway.ObjectUtilities.createArrayMap();
|
|
}
|
|
var name = this._qualifiedNameCache[index];
|
|
if (!name) {
|
|
name = this._qualifiedNameCache[index] = new Multiname([
|
|
this.namespaces[index]
|
|
], this.name, this.flags);
|
|
}
|
|
return name;
|
|
};
|
|
Multiname.prototype.hasQName = function (qn) {
|
|
true;
|
|
if (this.name !== qn.name) {
|
|
return false;
|
|
}
|
|
for (var i = 0; i < this.namespaces.length; i++) {
|
|
if (this.namespaces[i].isEqualTo(qn.namespaces[0])) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
Multiname.prototype.isAttribute = function () {
|
|
return this.flags & Multiname.ATTRIBUTE;
|
|
};
|
|
Multiname.prototype.isAnyName = function () {
|
|
return Multiname.isAnyName(this);
|
|
};
|
|
Multiname.prototype.isAnyNamespace = function () {
|
|
return !this.isRuntimeNamespace() && (this.namespaces.length === 0 || this.isAnyName() && this.namespaces.length !== 1);
|
|
};
|
|
Multiname.prototype.isRuntimeName = function () {
|
|
return !(!(this.flags & Multiname.RUNTIME_NAME));
|
|
};
|
|
Multiname.prototype.isRuntimeNamespace = function () {
|
|
return !(!(this.flags & Multiname.RUNTIME_NAMESPACE));
|
|
};
|
|
Multiname.prototype.isRuntime = function () {
|
|
return !(!(this.flags & (Multiname.RUNTIME_NAME | Multiname.RUNTIME_NAMESPACE)));
|
|
};
|
|
Multiname.prototype.isQName = function () {
|
|
return this.namespaces.length === 1 && !this.isAnyName();
|
|
};
|
|
Multiname.prototype.hasTypeParameter = function () {
|
|
return !(!this.typeParameter);
|
|
};
|
|
Multiname.prototype.getName = function () {
|
|
return this.name;
|
|
};
|
|
Multiname.prototype.getOriginalName = function () {
|
|
true;
|
|
var name = this.namespaces[0].uri;
|
|
if (name) {
|
|
name += '.';
|
|
}
|
|
return name + this.name;
|
|
};
|
|
Multiname.prototype.getNamespace = function () {
|
|
true;
|
|
true;
|
|
return this.namespaces[0];
|
|
};
|
|
Multiname.prototype.nameToString = function () {
|
|
if (this.isAnyName()) {
|
|
return '*';
|
|
} else {
|
|
var name = this.getName();
|
|
return this.isRuntimeName() ? '[]' : name;
|
|
}
|
|
};
|
|
Multiname.prototype.hasObjectName = function () {
|
|
return typeof this.name === 'object';
|
|
};
|
|
Multiname.prototype.toString = function () {
|
|
var str = this.isAttribute() ? '@' : '';
|
|
if (this.isAnyNamespace()) {
|
|
str += '*::' + this.nameToString();
|
|
} else if (this.isRuntimeNamespace()) {
|
|
str += '[]::' + this.nameToString();
|
|
} else if (this.namespaces.length === 1 && this.isQName()) {
|
|
str += this.namespaces[0].toString() + '::';
|
|
str += this.nameToString();
|
|
} else {
|
|
str += '{';
|
|
for (var i = 0, count = this.namespaces.length; i < count; i++) {
|
|
str += this.namespaces[i].toString();
|
|
if (i + 1 < count) {
|
|
str += ',';
|
|
}
|
|
}
|
|
str += '}::' + this.nameToString();
|
|
}
|
|
if (this.hasTypeParameter()) {
|
|
str += '<' + this.typeParameter.toString() + '>';
|
|
}
|
|
return str;
|
|
};
|
|
Multiname.ATTRIBUTE = 1;
|
|
Multiname.RUNTIME_NAMESPACE = 2;
|
|
Multiname.RUNTIME_NAME = 4;
|
|
Multiname._nextID = 0;
|
|
Multiname._simpleNameCache = Shumway.ObjectUtilities.createMap();
|
|
Multiname.Int = Multiname.getPublicQualifiedName('int');
|
|
Multiname.Uint = Multiname.getPublicQualifiedName('uint');
|
|
Multiname.Class = Multiname.getPublicQualifiedName('Class');
|
|
Multiname.Array = Multiname.getPublicQualifiedName('Array');
|
|
Multiname.Object = Multiname.getPublicQualifiedName('Object');
|
|
Multiname.String = Multiname.getPublicQualifiedName('String');
|
|
Multiname.Number = Multiname.getPublicQualifiedName('Number');
|
|
Multiname.Boolean = Multiname.getPublicQualifiedName('Boolean');
|
|
Multiname.Function = Multiname.getPublicQualifiedName('Function');
|
|
Multiname.XML = Multiname.getPublicQualifiedName('XML');
|
|
Multiname.XMLList = Multiname.getPublicQualifiedName('XMLList');
|
|
Multiname.TEMPORARY = new Multiname([], '');
|
|
return Multiname;
|
|
}();
|
|
ABC.Multiname = Multiname;
|
|
var MetaDataInfo = function () {
|
|
function MetaDataInfo(abc, stream) {
|
|
var strings = abc.constantPool.strings;
|
|
var name = this.name = strings[stream.readU30()];
|
|
var itemCount = stream.readU30();
|
|
var keys = [];
|
|
var items = [];
|
|
for (var i = 0; i < itemCount; i++) {
|
|
keys[i] = strings[stream.readU30()];
|
|
}
|
|
for (var i = 0; i < itemCount; i++) {
|
|
var key = keys[i];
|
|
items[i] = {
|
|
key: key,
|
|
value: strings[stream.readU30()]
|
|
};
|
|
if (key && name === 'native') {
|
|
true;
|
|
this[key] = items[i].value;
|
|
}
|
|
}
|
|
this.value = items;
|
|
}
|
|
MetaDataInfo.prototype.toString = function () {
|
|
return '[' + this.name + ']';
|
|
};
|
|
return MetaDataInfo;
|
|
}();
|
|
ABC.MetaDataInfo = MetaDataInfo;
|
|
(function (CONSTANT) {
|
|
CONSTANT[CONSTANT['Undefined'] = 0] = 'Undefined';
|
|
CONSTANT[CONSTANT['Utf8'] = 1] = 'Utf8';
|
|
CONSTANT[CONSTANT['Float'] = 2] = 'Float';
|
|
CONSTANT[CONSTANT['Int'] = 3] = 'Int';
|
|
CONSTANT[CONSTANT['UInt'] = 4] = 'UInt';
|
|
CONSTANT[CONSTANT['PrivateNs'] = 5] = 'PrivateNs';
|
|
CONSTANT[CONSTANT['Double'] = 6] = 'Double';
|
|
CONSTANT[CONSTANT['QName'] = 7] = 'QName';
|
|
CONSTANT[CONSTANT['Namespace'] = 8] = 'Namespace';
|
|
CONSTANT[CONSTANT['Multiname'] = 9] = 'Multiname';
|
|
CONSTANT[CONSTANT['False'] = 10] = 'False';
|
|
CONSTANT[CONSTANT['True'] = 11] = 'True';
|
|
CONSTANT[CONSTANT['Null'] = 12] = 'Null';
|
|
CONSTANT[CONSTANT['QNameA'] = 13] = 'QNameA';
|
|
CONSTANT[CONSTANT['MultinameA'] = 14] = 'MultinameA';
|
|
CONSTANT[CONSTANT['RTQName'] = 15] = 'RTQName';
|
|
CONSTANT[CONSTANT['RTQNameA'] = 16] = 'RTQNameA';
|
|
CONSTANT[CONSTANT['RTQNameL'] = 17] = 'RTQNameL';
|
|
CONSTANT[CONSTANT['RTQNameLA'] = 18] = 'RTQNameLA';
|
|
CONSTANT[CONSTANT['NameL'] = 19] = 'NameL';
|
|
CONSTANT[CONSTANT['NameLA'] = 20] = 'NameLA';
|
|
CONSTANT[CONSTANT['NamespaceSet'] = 21] = 'NamespaceSet';
|
|
CONSTANT[CONSTANT['PackageNamespace'] = 22] = 'PackageNamespace';
|
|
CONSTANT[CONSTANT['PackageInternalNs'] = 23] = 'PackageInternalNs';
|
|
CONSTANT[CONSTANT['ProtectedNamespace'] = 24] = 'ProtectedNamespace';
|
|
CONSTANT[CONSTANT['ExplicitNamespace'] = 25] = 'ExplicitNamespace';
|
|
CONSTANT[CONSTANT['StaticProtectedNs'] = 26] = 'StaticProtectedNs';
|
|
CONSTANT[CONSTANT['MultinameL'] = 27] = 'MultinameL';
|
|
CONSTANT[CONSTANT['MultinameLA'] = 28] = 'MultinameLA';
|
|
CONSTANT[CONSTANT['TypeName'] = 29] = 'TypeName';
|
|
CONSTANT[CONSTANT['ClassSealed'] = 1] = 'ClassSealed';
|
|
CONSTANT[CONSTANT['ClassFinal'] = 2] = 'ClassFinal';
|
|
CONSTANT[CONSTANT['ClassInterface'] = 4] = 'ClassInterface';
|
|
CONSTANT[CONSTANT['ClassProtectedNs'] = 8] = 'ClassProtectedNs';
|
|
}(ABC.CONSTANT || (ABC.CONSTANT = {})));
|
|
var CONSTANT = ABC.CONSTANT;
|
|
(function (METHOD) {
|
|
METHOD[METHOD['Arguments'] = 1] = 'Arguments';
|
|
METHOD[METHOD['Activation'] = 2] = 'Activation';
|
|
METHOD[METHOD['Needrest'] = 4] = 'Needrest';
|
|
METHOD[METHOD['HasOptional'] = 8] = 'HasOptional';
|
|
METHOD[METHOD['IgnoreRest'] = 16] = 'IgnoreRest';
|
|
METHOD[METHOD['Native'] = 32] = 'Native';
|
|
METHOD[METHOD['Setsdxns'] = 64] = 'Setsdxns';
|
|
METHOD[METHOD['HasParamNames'] = 128] = 'HasParamNames';
|
|
}(ABC.METHOD || (ABC.METHOD = {})));
|
|
var METHOD = ABC.METHOD;
|
|
(function (TRAIT) {
|
|
TRAIT[TRAIT['Slot'] = 0] = 'Slot';
|
|
TRAIT[TRAIT['Method'] = 1] = 'Method';
|
|
TRAIT[TRAIT['Getter'] = 2] = 'Getter';
|
|
TRAIT[TRAIT['Setter'] = 3] = 'Setter';
|
|
TRAIT[TRAIT['Class'] = 4] = 'Class';
|
|
TRAIT[TRAIT['Function'] = 5] = 'Function';
|
|
TRAIT[TRAIT['Const'] = 6] = 'Const';
|
|
}(ABC.TRAIT || (ABC.TRAIT = {})));
|
|
var TRAIT = ABC.TRAIT;
|
|
(function (ATTR) {
|
|
ATTR[ATTR['Final'] = 1] = 'Final';
|
|
ATTR[ATTR['Override'] = 2] = 'Override';
|
|
ATTR[ATTR['Metadata'] = 4] = 'Metadata';
|
|
}(ABC.ATTR || (ABC.ATTR = {})));
|
|
var ATTR = ABC.ATTR;
|
|
(function (SORT) {
|
|
SORT[SORT['CASEINSENSITIVE'] = 1] = 'CASEINSENSITIVE';
|
|
SORT[SORT['DESCENDING'] = 2] = 'DESCENDING';
|
|
SORT[SORT['UNIQUESORT'] = 4] = 'UNIQUESORT';
|
|
SORT[SORT['RETURNINDEXEDARRAY'] = 8] = 'RETURNINDEXEDARRAY';
|
|
SORT[SORT['NUMERIC'] = 16] = 'NUMERIC';
|
|
}(ABC.SORT || (ABC.SORT = {})));
|
|
var SORT = ABC.SORT;
|
|
(function (OP) {
|
|
OP[OP['bkpt'] = 1] = 'bkpt';
|
|
OP[OP['nop'] = 2] = 'nop';
|
|
OP[OP['throw'] = 3] = 'throw';
|
|
OP[OP['getsuper'] = 4] = 'getsuper';
|
|
OP[OP['setsuper'] = 5] = 'setsuper';
|
|
OP[OP['dxns'] = 6] = 'dxns';
|
|
OP[OP['dxnslate'] = 7] = 'dxnslate';
|
|
OP[OP['kill'] = 8] = 'kill';
|
|
OP[OP['label'] = 9] = 'label';
|
|
OP[OP['lf32x4'] = 10] = 'lf32x4';
|
|
OP[OP['sf32x4'] = 11] = 'sf32x4';
|
|
OP[OP['ifnlt'] = 12] = 'ifnlt';
|
|
OP[OP['ifnle'] = 13] = 'ifnle';
|
|
OP[OP['ifngt'] = 14] = 'ifngt';
|
|
OP[OP['ifnge'] = 15] = 'ifnge';
|
|
OP[OP['jump'] = 16] = 'jump';
|
|
OP[OP['iftrue'] = 17] = 'iftrue';
|
|
OP[OP['iffalse'] = 18] = 'iffalse';
|
|
OP[OP['ifeq'] = 19] = 'ifeq';
|
|
OP[OP['ifne'] = 20] = 'ifne';
|
|
OP[OP['iflt'] = 21] = 'iflt';
|
|
OP[OP['ifle'] = 22] = 'ifle';
|
|
OP[OP['ifgt'] = 23] = 'ifgt';
|
|
OP[OP['ifge'] = 24] = 'ifge';
|
|
OP[OP['ifstricteq'] = 25] = 'ifstricteq';
|
|
OP[OP['ifstrictne'] = 26] = 'ifstrictne';
|
|
OP[OP['lookupswitch'] = 27] = 'lookupswitch';
|
|
OP[OP['pushwith'] = 28] = 'pushwith';
|
|
OP[OP['popscope'] = 29] = 'popscope';
|
|
OP[OP['nextname'] = 30] = 'nextname';
|
|
OP[OP['hasnext'] = 31] = 'hasnext';
|
|
OP[OP['pushnull'] = 32] = 'pushnull';
|
|
OP[OP['c'] = 33] = 'c';
|
|
OP[OP['pushundefined'] = 33] = 'pushundefined';
|
|
OP[OP['pushfloat'] = 34] = 'pushfloat';
|
|
OP[OP['nextvalue'] = 35] = 'nextvalue';
|
|
OP[OP['pushbyte'] = 36] = 'pushbyte';
|
|
OP[OP['pushshort'] = 37] = 'pushshort';
|
|
OP[OP['pushtrue'] = 38] = 'pushtrue';
|
|
OP[OP['pushfalse'] = 39] = 'pushfalse';
|
|
OP[OP['pushnan'] = 40] = 'pushnan';
|
|
OP[OP['pop'] = 41] = 'pop';
|
|
OP[OP['dup'] = 42] = 'dup';
|
|
OP[OP['swap'] = 43] = 'swap';
|
|
OP[OP['pushstring'] = 44] = 'pushstring';
|
|
OP[OP['pushint'] = 45] = 'pushint';
|
|
OP[OP['pushuint'] = 46] = 'pushuint';
|
|
OP[OP['pushdouble'] = 47] = 'pushdouble';
|
|
OP[OP['pushscope'] = 48] = 'pushscope';
|
|
OP[OP['pushnamespace'] = 49] = 'pushnamespace';
|
|
OP[OP['hasnext2'] = 50] = 'hasnext2';
|
|
OP[OP['li8'] = 53] = 'li8';
|
|
OP[OP['li16'] = 54] = 'li16';
|
|
OP[OP['li32'] = 55] = 'li32';
|
|
OP[OP['lf32'] = 56] = 'lf32';
|
|
OP[OP['lf64'] = 57] = 'lf64';
|
|
OP[OP['si8'] = 58] = 'si8';
|
|
OP[OP['si16'] = 59] = 'si16';
|
|
OP[OP['si32'] = 60] = 'si32';
|
|
OP[OP['sf32'] = 61] = 'sf32';
|
|
OP[OP['sf64'] = 62] = 'sf64';
|
|
OP[OP['newfunction'] = 64] = 'newfunction';
|
|
OP[OP['call'] = 65] = 'call';
|
|
OP[OP['construct'] = 66] = 'construct';
|
|
OP[OP['callmethod'] = 67] = 'callmethod';
|
|
OP[OP['callstatic'] = 68] = 'callstatic';
|
|
OP[OP['callsuper'] = 69] = 'callsuper';
|
|
OP[OP['callproperty'] = 70] = 'callproperty';
|
|
OP[OP['returnvoid'] = 71] = 'returnvoid';
|
|
OP[OP['returnvalue'] = 72] = 'returnvalue';
|
|
OP[OP['constructsuper'] = 73] = 'constructsuper';
|
|
OP[OP['constructprop'] = 74] = 'constructprop';
|
|
OP[OP['callsuperid'] = 75] = 'callsuperid';
|
|
OP[OP['callproplex'] = 76] = 'callproplex';
|
|
OP[OP['callinterface'] = 77] = 'callinterface';
|
|
OP[OP['callsupervoid'] = 78] = 'callsupervoid';
|
|
OP[OP['callpropvoid'] = 79] = 'callpropvoid';
|
|
OP[OP['sxi1'] = 80] = 'sxi1';
|
|
OP[OP['sxi8'] = 81] = 'sxi8';
|
|
OP[OP['sxi16'] = 82] = 'sxi16';
|
|
OP[OP['applytype'] = 83] = 'applytype';
|
|
OP[OP['pushfloat4'] = 84] = 'pushfloat4';
|
|
OP[OP['newobject'] = 85] = 'newobject';
|
|
OP[OP['newarray'] = 86] = 'newarray';
|
|
OP[OP['newactivation'] = 87] = 'newactivation';
|
|
OP[OP['newclass'] = 88] = 'newclass';
|
|
OP[OP['getdescendants'] = 89] = 'getdescendants';
|
|
OP[OP['newcatch'] = 90] = 'newcatch';
|
|
OP[OP['findpropstrict'] = 93] = 'findpropstrict';
|
|
OP[OP['findproperty'] = 94] = 'findproperty';
|
|
OP[OP['finddef'] = 95] = 'finddef';
|
|
OP[OP['getlex'] = 96] = 'getlex';
|
|
OP[OP['setproperty'] = 97] = 'setproperty';
|
|
OP[OP['getlocal'] = 98] = 'getlocal';
|
|
OP[OP['setlocal'] = 99] = 'setlocal';
|
|
OP[OP['getglobalscope'] = 100] = 'getglobalscope';
|
|
OP[OP['getscopeobject'] = 101] = 'getscopeobject';
|
|
OP[OP['getproperty'] = 102] = 'getproperty';
|
|
OP[OP['getouterscope'] = 103] = 'getouterscope';
|
|
OP[OP['initproperty'] = 104] = 'initproperty';
|
|
OP[OP['setpropertylate'] = 105] = 'setpropertylate';
|
|
OP[OP['deleteproperty'] = 106] = 'deleteproperty';
|
|
OP[OP['deletepropertylate'] = 107] = 'deletepropertylate';
|
|
OP[OP['getslot'] = 108] = 'getslot';
|
|
OP[OP['setslot'] = 109] = 'setslot';
|
|
OP[OP['getglobalslot'] = 110] = 'getglobalslot';
|
|
OP[OP['setglobalslot'] = 111] = 'setglobalslot';
|
|
OP[OP['convert_s'] = 112] = 'convert_s';
|
|
OP[OP['esc_xelem'] = 113] = 'esc_xelem';
|
|
OP[OP['esc_xattr'] = 114] = 'esc_xattr';
|
|
OP[OP['convert_i'] = 115] = 'convert_i';
|
|
OP[OP['convert_u'] = 116] = 'convert_u';
|
|
OP[OP['convert_d'] = 117] = 'convert_d';
|
|
OP[OP['convert_b'] = 118] = 'convert_b';
|
|
OP[OP['convert_o'] = 119] = 'convert_o';
|
|
OP[OP['checkfilter'] = 120] = 'checkfilter';
|
|
OP[OP['convert_f'] = 121] = 'convert_f';
|
|
OP[OP['unplus'] = 122] = 'unplus';
|
|
OP[OP['convert_f4'] = 123] = 'convert_f4';
|
|
OP[OP['coerce'] = 128] = 'coerce';
|
|
OP[OP['coerce_b'] = 129] = 'coerce_b';
|
|
OP[OP['coerce_a'] = 130] = 'coerce_a';
|
|
OP[OP['coerce_i'] = 131] = 'coerce_i';
|
|
OP[OP['coerce_d'] = 132] = 'coerce_d';
|
|
OP[OP['coerce_s'] = 133] = 'coerce_s';
|
|
OP[OP['astype'] = 134] = 'astype';
|
|
OP[OP['astypelate'] = 135] = 'astypelate';
|
|
OP[OP['coerce_u'] = 136] = 'coerce_u';
|
|
OP[OP['coerce_o'] = 137] = 'coerce_o';
|
|
OP[OP['negate'] = 144] = 'negate';
|
|
OP[OP['increment'] = 145] = 'increment';
|
|
OP[OP['inclocal'] = 146] = 'inclocal';
|
|
OP[OP['decrement'] = 147] = 'decrement';
|
|
OP[OP['declocal'] = 148] = 'declocal';
|
|
OP[OP['typeof'] = 149] = 'typeof';
|
|
OP[OP['not'] = 150] = 'not';
|
|
OP[OP['bitnot'] = 151] = 'bitnot';
|
|
OP[OP['add'] = 160] = 'add';
|
|
OP[OP['subtract'] = 161] = 'subtract';
|
|
OP[OP['multiply'] = 162] = 'multiply';
|
|
OP[OP['divide'] = 163] = 'divide';
|
|
OP[OP['modulo'] = 164] = 'modulo';
|
|
OP[OP['lshift'] = 165] = 'lshift';
|
|
OP[OP['rshift'] = 166] = 'rshift';
|
|
OP[OP['urshift'] = 167] = 'urshift';
|
|
OP[OP['bitand'] = 168] = 'bitand';
|
|
OP[OP['bitor'] = 169] = 'bitor';
|
|
OP[OP['bitxor'] = 170] = 'bitxor';
|
|
OP[OP['equals'] = 171] = 'equals';
|
|
OP[OP['strictequals'] = 172] = 'strictequals';
|
|
OP[OP['lessthan'] = 173] = 'lessthan';
|
|
OP[OP['lessequals'] = 174] = 'lessequals';
|
|
OP[OP['greaterthan'] = 175] = 'greaterthan';
|
|
OP[OP['greaterequals'] = 176] = 'greaterequals';
|
|
OP[OP['instanceof'] = 177] = 'instanceof';
|
|
OP[OP['istype'] = 178] = 'istype';
|
|
OP[OP['istypelate'] = 179] = 'istypelate';
|
|
OP[OP['in'] = 180] = 'in';
|
|
OP[OP['increment_i'] = 192] = 'increment_i';
|
|
OP[OP['decrement_i'] = 193] = 'decrement_i';
|
|
OP[OP['inclocal_i'] = 194] = 'inclocal_i';
|
|
OP[OP['declocal_i'] = 195] = 'declocal_i';
|
|
OP[OP['negate_i'] = 196] = 'negate_i';
|
|
OP[OP['add_i'] = 197] = 'add_i';
|
|
OP[OP['subtract_i'] = 198] = 'subtract_i';
|
|
OP[OP['multiply_i'] = 199] = 'multiply_i';
|
|
OP[OP['getlocal0'] = 208] = 'getlocal0';
|
|
OP[OP['getlocal1'] = 209] = 'getlocal1';
|
|
OP[OP['getlocal2'] = 210] = 'getlocal2';
|
|
OP[OP['getlocal3'] = 211] = 'getlocal3';
|
|
OP[OP['setlocal0'] = 212] = 'setlocal0';
|
|
OP[OP['setlocal1'] = 213] = 'setlocal1';
|
|
OP[OP['setlocal2'] = 214] = 'setlocal2';
|
|
OP[OP['setlocal3'] = 215] = 'setlocal3';
|
|
OP[OP['invalid'] = 237] = 'invalid';
|
|
OP[OP['debug'] = 239] = 'debug';
|
|
OP[OP['debugline'] = 240] = 'debugline';
|
|
OP[OP['debugfile'] = 241] = 'debugfile';
|
|
OP[OP['bkptline'] = 242] = 'bkptline';
|
|
OP[OP['timestamp'] = 243] = 'timestamp';
|
|
}(ABC.OP || (ABC.OP = {})));
|
|
var OP = ABC.OP;
|
|
var ConstantPool = function () {
|
|
function ConstantPool(stream, abc) {
|
|
var n;
|
|
var ints = [
|
|
0
|
|
];
|
|
n = stream.readU30();
|
|
for (var i = 1; i < n; ++i) {
|
|
ints.push(stream.readS32());
|
|
}
|
|
var uints = [
|
|
0
|
|
];
|
|
n = stream.readU30();
|
|
for (var i = 1; i < n; ++i) {
|
|
uints.push(stream.readU32());
|
|
}
|
|
var doubles = [
|
|
NaN
|
|
];
|
|
n = stream.readU30();
|
|
for (var i = 1; i < n; ++i) {
|
|
doubles.push(stream.readDouble());
|
|
}
|
|
Timer.start('Parse Strings');
|
|
var strings = [
|
|
''
|
|
];
|
|
n = stream.readU30();
|
|
for (var i = 1; i < n; ++i) {
|
|
strings.push(stream.readUTFString(stream.readU30()));
|
|
}
|
|
this.positionAfterUTFStrings = stream.position;
|
|
Timer.stop();
|
|
this.ints = ints;
|
|
this.uints = uints;
|
|
this.doubles = doubles;
|
|
this.strings = strings;
|
|
Timer.start('Parse Namespaces');
|
|
var namespaces = [
|
|
undefined
|
|
];
|
|
n = stream.readU30();
|
|
for (var i = 1; i < n; ++i) {
|
|
namespaces.push(Namespace.parse(this, stream, abc.hash + i));
|
|
}
|
|
Timer.stop();
|
|
Timer.start('Parse Namespace Sets');
|
|
var namespaceSets = [
|
|
undefined
|
|
];
|
|
n = stream.readU30();
|
|
for (var i = 1; i < n; ++i) {
|
|
var count = stream.readU30();
|
|
var set = [];
|
|
set.runtimeId = ConstantPool._nextNamespaceSetID++;
|
|
for (var j = 0; j < count; ++j) {
|
|
set.push(namespaces[stream.readU30()]);
|
|
}
|
|
namespaceSets.push(set);
|
|
}
|
|
Timer.stop();
|
|
this.namespaces = namespaces;
|
|
this.namespaceSets = namespaceSets;
|
|
Timer.start('Parse Multinames');
|
|
var multinames = [
|
|
undefined
|
|
];
|
|
var patchFactoryTypes = [];
|
|
n = stream.readU30();
|
|
for (var i = 1; i < n; ++i) {
|
|
multinames.push(Multiname.parse(this, stream, multinames, patchFactoryTypes));
|
|
}
|
|
Timer.stop();
|
|
this.multinames = multinames;
|
|
}
|
|
ConstantPool.prototype.getValue = function (kind, index) {
|
|
switch (kind) {
|
|
case 3:
|
|
return this.ints[index];
|
|
case 4:
|
|
return this.uints[index];
|
|
case 6:
|
|
return this.doubles[index];
|
|
case 1:
|
|
return this.strings[index];
|
|
case 11:
|
|
return true;
|
|
case 10:
|
|
return false;
|
|
case 12:
|
|
return null;
|
|
case 0:
|
|
return undefined;
|
|
case 8:
|
|
case 23:
|
|
return this.namespaces[index];
|
|
case 7:
|
|
case 14:
|
|
case 15:
|
|
case 16:
|
|
case 17:
|
|
case 18:
|
|
case 19:
|
|
case 20:
|
|
return this.multinames[index];
|
|
case 2:
|
|
Shumway.Debug.warning('TODO: CONSTANT.Float may be deprecated?');
|
|
break;
|
|
default:
|
|
true;
|
|
}
|
|
};
|
|
ConstantPool._nextNamespaceSetID = 1;
|
|
return ConstantPool;
|
|
}();
|
|
ABC.ConstantPool = ConstantPool;
|
|
}(AVM2.ABC || (AVM2.ABC = {})));
|
|
var ABC = AVM2.ABC;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
var AbcFile = Shumway.AVM2.ABC.AbcFile;
|
|
var AbcStream = Shumway.AVM2.ABC.AbcStream;
|
|
var ConstantPool = Shumway.AVM2.ABC.ConstantPool;
|
|
var ClassInfo = Shumway.AVM2.ABC.ClassInfo;
|
|
var MetaDataInfo = Shumway.AVM2.ABC.MetaDataInfo;
|
|
var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo;
|
|
var ScriptInfo = Shumway.AVM2.ABC.ScriptInfo;
|
|
var Trait = Shumway.AVM2.ABC.Trait;
|
|
var MethodInfo = Shumway.AVM2.ABC.MethodInfo;
|
|
var Multiname = Shumway.AVM2.ABC.Multiname;
|
|
var ASNamespace = Shumway.AVM2.ABC.Namespace;
|
|
var AbcFile = Shumway.AVM2.ABC.AbcFile;
|
|
var AbcStream = Shumway.AVM2.ABC.AbcStream;
|
|
var ConstantPool = Shumway.AVM2.ABC.ConstantPool;
|
|
var ClassInfo = Shumway.AVM2.ABC.ClassInfo;
|
|
var MetaDataInfo = Shumway.AVM2.ABC.MetaDataInfo;
|
|
var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo;
|
|
var ScriptInfo = Shumway.AVM2.ABC.ScriptInfo;
|
|
var Trait = Shumway.AVM2.ABC.Trait;
|
|
var MethodInfo = Shumway.AVM2.ABC.MethodInfo;
|
|
var Multiname = Shumway.AVM2.ABC.Multiname;
|
|
var ASNamespace = Shumway.AVM2.ABC.Namespace;
|
|
var Bytecode = function () {
|
|
function Bytecode(code) {
|
|
var op = code.readU8();
|
|
this.op = op;
|
|
this.originalPosition = code.position;
|
|
var opdesc = Shumway.AVM2.opcodeTable[op];
|
|
if (!opdesc) {
|
|
unexpected('Unknown Op ' + op);
|
|
}
|
|
this.canThrow = opdesc.canThrow;
|
|
var i, n;
|
|
switch (op) {
|
|
case OP_lookupswitch:
|
|
var defaultOffset = code.readS24();
|
|
this.offsets = [];
|
|
var n = code.readU30() + 1;
|
|
for (i = 0; i < n; i++) {
|
|
this.offsets.push(code.readS24());
|
|
}
|
|
this.offsets.push(defaultOffset);
|
|
break;
|
|
default:
|
|
for (i = 0, n = opdesc.operands.length; i < n; i++) {
|
|
var operand = opdesc.operands[i];
|
|
switch (operand.size) {
|
|
case 'u08':
|
|
this[operand.name] = code.readU8();
|
|
break;
|
|
case 's08':
|
|
this[operand.name] = code.readS8();
|
|
break;
|
|
case 's16':
|
|
this[operand.name] = code.readS16();
|
|
break;
|
|
case 's24':
|
|
this[operand.name] = code.readS24();
|
|
break;
|
|
case 'u30':
|
|
this[operand.name] = code.readU30();
|
|
break;
|
|
case 'u32':
|
|
this[operand.name] = code.readU32();
|
|
break;
|
|
default:
|
|
unexpected();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Bytecode.prototype = {
|
|
makeBlockHead: function makeBlockHead(id) {
|
|
if (this.succs) {
|
|
return id;
|
|
}
|
|
this.bid = id;
|
|
this.succs = [];
|
|
this.preds = [];
|
|
this.dominatees = [];
|
|
return id + 1;
|
|
},
|
|
trace: function trace(writer) {
|
|
if (!this.succs) {
|
|
return;
|
|
}
|
|
writer.writeLn('#' + this.bid);
|
|
},
|
|
toString: function toString(abc) {
|
|
var opDescription = Shumway.AVM2.opcodeTable[this.op];
|
|
var str = opDescription.name.padRight(' ', 20);
|
|
var i, j;
|
|
if (this.op === OP_lookupswitch) {
|
|
str += 'targets:';
|
|
for (i = 0, j = this.targets.length; i < j; i++) {
|
|
str += (i > 0 ? ',' : '') + this.targets[i].position;
|
|
}
|
|
} else {
|
|
for (i = 0, j = opDescription.operands.length; i < j; i++) {
|
|
var operand = opDescription.operands[i];
|
|
if (operand.name === 'offset') {
|
|
str += 'target:' + this.target.position;
|
|
} else {
|
|
str += operand.name + ': ';
|
|
var value = this[operand.name];
|
|
if (abc) {
|
|
switch (operand.type) {
|
|
case '':
|
|
str += value;
|
|
break;
|
|
case 'I':
|
|
str += abc.constantPool.ints[value];
|
|
break;
|
|
case 'U':
|
|
str += abc.constantPool.uints[value];
|
|
break;
|
|
case 'D':
|
|
str += abc.constantPool.doubles[value];
|
|
break;
|
|
case 'S':
|
|
str += abc.constantPool.strings[value];
|
|
break;
|
|
case 'N':
|
|
str += abc.constantPool.namespaces[value];
|
|
break;
|
|
case 'CI':
|
|
str += abc.classes[value];
|
|
break;
|
|
case 'M':
|
|
str += abc.constantPool.multinames[value];
|
|
break;
|
|
default:
|
|
str += '?';
|
|
break;
|
|
}
|
|
} else {
|
|
str += value;
|
|
}
|
|
}
|
|
if (i < j - 1) {
|
|
str += ', ';
|
|
}
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
};
|
|
return Bytecode;
|
|
}();
|
|
var Analysis = function () {
|
|
function blockSetClass(length, blockById) {
|
|
var BlockSet = BitSetFunctor(length);
|
|
var ADDRESS_BITS_PER_WORD = BlockSet.ADDRESS_BITS_PER_WORD;
|
|
var BITS_PER_WORD = BlockSet.BITS_PER_WORD;
|
|
var BIT_INDEX_MASK = BlockSet.BIT_INDEX_MASK;
|
|
BlockSet.singleton = function singleton(b) {
|
|
var bs = new BlockSet();
|
|
bs.set(b.bid);
|
|
bs.count = 1;
|
|
bs.dirty = 0;
|
|
return bs;
|
|
};
|
|
BlockSet.fromBlocks = function fromArray(other) {
|
|
var bs = new BlockSet();
|
|
bs.setBlocks(other);
|
|
return bs;
|
|
};
|
|
var Bsp = BlockSet.prototype;
|
|
if (BlockSet.singleword) {
|
|
Bsp.forEachBlock = function forEach(fn) {
|
|
true;
|
|
var byId = blockById;
|
|
var word = this.bits;
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
fn(byId[k]);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Bsp.choose = function choose() {
|
|
var byId = blockById;
|
|
var word = this.bits;
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
return byId[k];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Bsp.members = function members() {
|
|
var byId = blockById;
|
|
var set = [];
|
|
var word = this.bits;
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
set.push(byId[k]);
|
|
}
|
|
}
|
|
}
|
|
return set;
|
|
};
|
|
Bsp.setBlocks = function setBlocks(bs) {
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bs.length; i < j; i++) {
|
|
var id = bs[i].bid;
|
|
bits |= 1 << (id & BIT_INDEX_MASK);
|
|
}
|
|
this.bits = bits;
|
|
};
|
|
} else {
|
|
Bsp.forEachBlock = function forEach(fn) {
|
|
true;
|
|
var byId = blockById;
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var word = bits[i];
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
fn(byId[i * BITS_PER_WORD + k]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Bsp.choose = function choose() {
|
|
var byId = blockById;
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var word = bits[i];
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
return byId[i * BITS_PER_WORD + k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Bsp.members = function members() {
|
|
var byId = blockById;
|
|
var set = [];
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var word = bits[i];
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
set.push(byId[i * BITS_PER_WORD + k]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return set;
|
|
};
|
|
Bsp.setBlocks = function setBlocks(bs) {
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bs.length; i < j; i++) {
|
|
var id = bs[i].bid;
|
|
bits[id >> ADDRESS_BITS_PER_WORD] |= 1 << (id & BIT_INDEX_MASK);
|
|
}
|
|
};
|
|
}
|
|
return BlockSet;
|
|
}
|
|
function Analysis(method) {
|
|
Counter.count('Analysis');
|
|
this.method = method;
|
|
if (this.method.code) {
|
|
Timer.start('Normalize');
|
|
this.normalizeBytecode();
|
|
Timer.stop();
|
|
}
|
|
}
|
|
Analysis.prototype = {
|
|
normalizeBytecode: function normalizeBytecode() {
|
|
function getInvalidTarget(cache, offset) {
|
|
if (cache && cache[offset]) {
|
|
return cache[offset];
|
|
}
|
|
var code = Object.create(Bytecode.prototype);
|
|
code.op = OP_invalid;
|
|
code.position = offset;
|
|
cache && (cache[offset] = code);
|
|
return code;
|
|
}
|
|
var method = this.method;
|
|
function accessLocal(index) {
|
|
if (index-- === 0)
|
|
return;
|
|
if (index < method.parameters.length) {
|
|
method.parameters[index].isUsed = true;
|
|
}
|
|
}
|
|
var bytecodesOffset = [];
|
|
var bytecodes = [];
|
|
var codeStream = new AbcStream(this.method.code);
|
|
var code;
|
|
while (codeStream.remaining() > 0) {
|
|
var pos = codeStream.position;
|
|
code = new Bytecode(codeStream);
|
|
switch (code.op) {
|
|
case OP_nop:
|
|
case OP_label:
|
|
bytecodesOffset[pos] = bytecodes.length;
|
|
continue;
|
|
case OP_lookupswitch:
|
|
this.method.hasLookupSwitches = true;
|
|
code.targets = [];
|
|
var offsets = code.offsets;
|
|
for (var i = 0, j = offsets.length; i < j; i++) {
|
|
offsets[i] += pos;
|
|
}
|
|
break;
|
|
case OP_jump:
|
|
case OP_iflt:
|
|
case OP_ifnlt:
|
|
case OP_ifle:
|
|
case OP_ifnle:
|
|
case OP_ifgt:
|
|
case OP_ifngt:
|
|
case OP_ifge:
|
|
case OP_ifnge:
|
|
case OP_ifeq:
|
|
case OP_ifne:
|
|
case OP_ifstricteq:
|
|
case OP_ifstrictne:
|
|
case OP_iftrue:
|
|
case OP_iffalse:
|
|
code.offset += codeStream.position;
|
|
break;
|
|
case OP_getlocal0:
|
|
case OP_getlocal1:
|
|
case OP_getlocal2:
|
|
case OP_getlocal3:
|
|
accessLocal(code.op - OP_getlocal0);
|
|
break;
|
|
case OP_getlocal:
|
|
accessLocal(code.index);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
code.position = bytecodes.length;
|
|
bytecodesOffset[pos] = bytecodes.length;
|
|
bytecodes.push(code);
|
|
}
|
|
var invalidJumps = {};
|
|
var newOffset;
|
|
for (var pc = 0, end = bytecodes.length; pc < end; pc++) {
|
|
code = bytecodes[pc];
|
|
switch (code.op) {
|
|
case OP_lookupswitch:
|
|
var offsets = code.offsets;
|
|
for (var i = 0, j = offsets.length; i < j; i++) {
|
|
newOffset = bytecodesOffset[offsets[i]];
|
|
code.targets.push(bytecodes[newOffset] || getInvalidTarget(invalidJumps, offsets[i]));
|
|
offsets[i] = newOffset;
|
|
}
|
|
break;
|
|
case OP_jump:
|
|
case OP_iflt:
|
|
case OP_ifnlt:
|
|
case OP_ifle:
|
|
case OP_ifnle:
|
|
case OP_ifgt:
|
|
case OP_ifngt:
|
|
case OP_ifge:
|
|
case OP_ifnge:
|
|
case OP_ifeq:
|
|
case OP_ifne:
|
|
case OP_ifstricteq:
|
|
case OP_ifstrictne:
|
|
case OP_iftrue:
|
|
case OP_iffalse:
|
|
newOffset = bytecodesOffset[code.offset];
|
|
code.target = bytecodes[newOffset] || getInvalidTarget(invalidJumps, code.offset);
|
|
code.offset = newOffset;
|
|
break;
|
|
default:
|
|
}
|
|
}
|
|
this.bytecodes = bytecodes;
|
|
var exceptions = this.method.exceptions;
|
|
for (var i = 0, j = exceptions.length; i < j; i++) {
|
|
var ex = exceptions[i];
|
|
ex.start = bytecodesOffset[ex.start];
|
|
ex.end = bytecodesOffset[ex.end];
|
|
ex.offset = bytecodesOffset[ex.target];
|
|
ex.target = bytecodes[ex.offset];
|
|
ex.target.exception = ex;
|
|
}
|
|
},
|
|
detectBasicBlocks: function detectBasicBlocks() {
|
|
var bytecodes = this.bytecodes;
|
|
var exceptions = this.method.exceptions;
|
|
var hasExceptions = exceptions.length > 0;
|
|
var blockById = {};
|
|
var code;
|
|
var pc, end;
|
|
var id = 0;
|
|
function tryTargets(block) {
|
|
var targets = [];
|
|
for (var i = 0, j = exceptions.length; i < j; i++) {
|
|
var ex = exceptions[i];
|
|
if (block.position >= ex.start && block.end.position <= ex.end) {
|
|
targets.push(ex.target);
|
|
}
|
|
}
|
|
return targets;
|
|
}
|
|
id = bytecodes[0].makeBlockHead(id);
|
|
for (pc = 0, end = bytecodes.length - 1; pc < end; pc++) {
|
|
code = bytecodes[pc];
|
|
switch (code.op) {
|
|
case OP_returnvoid:
|
|
case OP_returnvalue:
|
|
case OP_throw:
|
|
id = bytecodes[pc + 1].makeBlockHead(id);
|
|
break;
|
|
case OP_lookupswitch:
|
|
var targets = code.targets;
|
|
for (var i = 0, j = targets.length; i < j; i++) {
|
|
id = targets[i].makeBlockHead(id);
|
|
}
|
|
id = bytecodes[pc + 1].makeBlockHead(id);
|
|
break;
|
|
case OP_jump:
|
|
case OP_iflt:
|
|
case OP_ifnlt:
|
|
case OP_ifle:
|
|
case OP_ifnle:
|
|
case OP_ifgt:
|
|
case OP_ifngt:
|
|
case OP_ifge:
|
|
case OP_ifnge:
|
|
case OP_ifeq:
|
|
case OP_ifne:
|
|
case OP_ifstricteq:
|
|
case OP_ifstrictne:
|
|
case OP_iftrue:
|
|
case OP_iffalse:
|
|
id = code.target.makeBlockHead(id);
|
|
id = bytecodes[pc + 1].makeBlockHead(id);
|
|
break;
|
|
default:
|
|
}
|
|
}
|
|
code = bytecodes[end];
|
|
switch (code.op) {
|
|
case OP_returnvoid:
|
|
case OP_returnvalue:
|
|
case OP_throw:
|
|
break;
|
|
case OP_lookupswitch:
|
|
var targets = code.targets;
|
|
for (var i = 0, j = targets.length; i < j; i++) {
|
|
id = targets[i].makeBlockHead(id);
|
|
}
|
|
break;
|
|
case OP_jump:
|
|
id = code.target.makeBlockHead(id);
|
|
break;
|
|
case OP_iflt:
|
|
case OP_ifnlt:
|
|
case OP_ifle:
|
|
case OP_ifnle:
|
|
case OP_ifgt:
|
|
case OP_ifngt:
|
|
case OP_ifge:
|
|
case OP_ifnge:
|
|
case OP_ifeq:
|
|
case OP_ifne:
|
|
case OP_ifstricteq:
|
|
case OP_ifstrictne:
|
|
case OP_iftrue:
|
|
case OP_iffalse:
|
|
id = code.target.makeBlockHead(id);
|
|
bytecodes[pc + 1] = getInvalidTarget(null, pc + 1);
|
|
id = bytecodes[pc + 1].makeBlockHead(id);
|
|
break;
|
|
default:
|
|
}
|
|
if (hasExceptions) {
|
|
for (var i = 0, j = exceptions.length; i < j; i++) {
|
|
var ex = exceptions[i];
|
|
var tryStart = bytecodes[ex.start];
|
|
var afterTry = bytecodes[ex.end + 1];
|
|
id = tryStart.makeBlockHead(id);
|
|
if (afterTry) {
|
|
id = afterTry.makeBlockHead(id);
|
|
}
|
|
id = ex.target.makeBlockHead(id);
|
|
}
|
|
}
|
|
var currentBlock = bytecodes[0];
|
|
for (pc = 1, end = bytecodes.length; pc < end; pc++) {
|
|
if (!bytecodes[pc].succs) {
|
|
continue;
|
|
}
|
|
true;
|
|
blockById[currentBlock.bid] = currentBlock;
|
|
code = bytecodes[pc - 1];
|
|
currentBlock.end = code;
|
|
var nextBlock = bytecodes[pc];
|
|
switch (code.op) {
|
|
case OP_returnvoid:
|
|
case OP_returnvalue:
|
|
case OP_throw:
|
|
break;
|
|
case OP_lookupswitch:
|
|
for (var i = 0, j = code.targets.length; i < j; i++) {
|
|
currentBlock.succs.push(code.targets[i]);
|
|
}
|
|
break;
|
|
case OP_jump:
|
|
currentBlock.succs.push(code.target);
|
|
break;
|
|
case OP_iflt:
|
|
case OP_ifnlt:
|
|
case OP_ifle:
|
|
case OP_ifnle:
|
|
case OP_ifgt:
|
|
case OP_ifngt:
|
|
case OP_ifge:
|
|
case OP_ifnge:
|
|
case OP_ifeq:
|
|
case OP_ifne:
|
|
case OP_ifstricteq:
|
|
case OP_ifstrictne:
|
|
case OP_iftrue:
|
|
case OP_iffalse:
|
|
currentBlock.succs.push(code.target);
|
|
if (code.target !== nextBlock) {
|
|
currentBlock.succs.push(nextBlock);
|
|
}
|
|
break;
|
|
default:
|
|
currentBlock.succs.push(nextBlock);
|
|
}
|
|
if (hasExceptions) {
|
|
var targets = tryTargets(currentBlock);
|
|
currentBlock.hasCatches = targets.length > 0;
|
|
currentBlock.succs.push.apply(currentBlock.succs, targets);
|
|
}
|
|
currentBlock = nextBlock;
|
|
}
|
|
blockById[currentBlock.bid] = currentBlock;
|
|
code = bytecodes[end - 1];
|
|
switch (code.op) {
|
|
case OP_lookupswitch:
|
|
for (var i = 0, j = code.targets.length; i < j; i++) {
|
|
currentBlock.succs.push(code.targets[i]);
|
|
}
|
|
break;
|
|
case OP_jump:
|
|
currentBlock.succs.push(code.target);
|
|
break;
|
|
default:
|
|
}
|
|
currentBlock.end = code;
|
|
this.BlockSet = blockSetClass(id, blockById);
|
|
},
|
|
normalizeReachableBlocks: function normalizeReachableBlocks() {
|
|
var root = this.bytecodes[0];
|
|
true;
|
|
var ONCE = 1;
|
|
var BUNCH_OF_TIMES = 2;
|
|
var BlockSet = this.BlockSet;
|
|
var blocks = [];
|
|
var visited = {};
|
|
var ancestors = {};
|
|
var worklist = [
|
|
root
|
|
];
|
|
var node;
|
|
ancestors[root.bid] = true;
|
|
while (node = worklist.top()) {
|
|
if (visited[node.bid]) {
|
|
if (visited[node.bid] === ONCE) {
|
|
visited[node.bid] = BUNCH_OF_TIMES;
|
|
blocks.push(node);
|
|
var succs = node.succs;
|
|
for (var i = 0, j = succs.length; i < j; i++) {
|
|
succs[i].preds.push(node);
|
|
}
|
|
}
|
|
ancestors[node.bid] = false;
|
|
worklist.pop();
|
|
continue;
|
|
}
|
|
visited[node.bid] = ONCE;
|
|
ancestors[node.bid] = true;
|
|
var succs = node.succs;
|
|
for (var i = 0, j = succs.length; i < j; i++) {
|
|
var s = succs[i];
|
|
if (ancestors[s.bid]) {
|
|
if (!node.spbacks) {
|
|
node.spbacks = new BlockSet();
|
|
}
|
|
node.spbacks.set(s.bid);
|
|
}
|
|
!visited[s.bid] && worklist.push(s);
|
|
}
|
|
}
|
|
this.blocks = blocks.reverse();
|
|
},
|
|
computeDominance: function computeDominance() {
|
|
function intersectDominators(doms, b1, b2) {
|
|
var finger1 = b1;
|
|
var finger2 = b2;
|
|
while (finger1 !== finger2) {
|
|
while (finger1 > finger2) {
|
|
finger1 = doms[finger1];
|
|
}
|
|
while (finger2 > finger1) {
|
|
finger2 = doms[finger2];
|
|
}
|
|
}
|
|
return finger1;
|
|
}
|
|
var blocks = this.blocks;
|
|
var n = blocks.length;
|
|
var doms = new Array(n);
|
|
doms[0] = 0;
|
|
var rpo = {};
|
|
for (var b = 0; b < n; b++) {
|
|
rpo[blocks[b].bid] = b;
|
|
}
|
|
var changed = true;
|
|
while (changed) {
|
|
changed = false;
|
|
for (var b = 1; b < n; b++) {
|
|
var preds = blocks[b].preds;
|
|
var j = preds.length;
|
|
var newIdom = rpo[preds[0].bid];
|
|
if (!(newIdom in doms)) {
|
|
for (var i = 1; i < j; i++) {
|
|
newIdom = rpo[preds[i].bid];
|
|
if (newIdom in doms) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
true;
|
|
for (var i = 0; i < j; i++) {
|
|
var p = rpo[preds[i].bid];
|
|
if (p === newIdom) {
|
|
continue;
|
|
}
|
|
if (p in doms) {
|
|
newIdom = intersectDominators(doms, p, newIdom);
|
|
}
|
|
}
|
|
if (doms[b] !== newIdom) {
|
|
doms[b] = newIdom;
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
blocks[0].dominator = blocks[0];
|
|
var block;
|
|
for (var b = 1; b < n; b++) {
|
|
block = blocks[b];
|
|
var idom = blocks[doms[b]];
|
|
block.dominator = idom;
|
|
idom.dominatees.push(block);
|
|
block.npreds = block.preds.length;
|
|
}
|
|
var worklist = [
|
|
blocks[0]
|
|
];
|
|
blocks[0].level || (blocks[0].level = 0);
|
|
while (block = worklist.shift()) {
|
|
var dominatees = block.dominatees;
|
|
for (var i = 0, j = dominatees.length; i < j; i++) {
|
|
dominatees[i].level = block.level + 1;
|
|
}
|
|
worklist.push.apply(worklist, dominatees);
|
|
}
|
|
},
|
|
analyzeControlFlow: function analyzeControlFlow() {
|
|
true;
|
|
this.detectBasicBlocks();
|
|
this.normalizeReachableBlocks();
|
|
this.computeDominance();
|
|
this.analyzedControlFlow = true;
|
|
return true;
|
|
},
|
|
markLoops: function markLoops() {
|
|
if (!this.analyzedControlFlow && !this.analyzeControlFlow()) {
|
|
return false;
|
|
}
|
|
var BlockSet = this.BlockSet;
|
|
function findSCCs(root) {
|
|
var preorderId = 1;
|
|
var preorder = {};
|
|
var assigned = {};
|
|
var unconnectedNodes = [];
|
|
var pendingNodes = [];
|
|
var sccs = [];
|
|
var level = root.level + 1;
|
|
var worklist = [
|
|
root
|
|
];
|
|
var node;
|
|
var u, s;
|
|
while (node = worklist.top()) {
|
|
if (preorder[node.bid]) {
|
|
if (pendingNodes.peek() === node) {
|
|
pendingNodes.pop();
|
|
var scc = [];
|
|
do {
|
|
u = unconnectedNodes.pop();
|
|
assigned[u.bid] = true;
|
|
scc.push(u);
|
|
} while (u !== node);
|
|
if (scc.length > 1 || u.spbacks && u.spbacks.get(u.bid)) {
|
|
sccs.push(scc);
|
|
}
|
|
}
|
|
worklist.pop();
|
|
continue;
|
|
}
|
|
preorder[node.bid] = preorderId++;
|
|
unconnectedNodes.push(node);
|
|
pendingNodes.push(node);
|
|
var succs = node.succs;
|
|
for (var i = 0, j = succs.length; i < j; i++) {
|
|
s = succs[i];
|
|
if (s.level < level) {
|
|
continue;
|
|
}
|
|
var sid = s.bid;
|
|
if (!preorder[sid]) {
|
|
worklist.push(s);
|
|
} else if (!assigned[sid]) {
|
|
while (preorder[pendingNodes.peek().bid] > preorder[sid]) {
|
|
pendingNodes.pop();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return sccs;
|
|
}
|
|
function findLoopHeads(blocks) {
|
|
var heads = new BlockSet();
|
|
for (var i = 0, j = blocks.length; i < j; i++) {
|
|
var block = blocks[i];
|
|
var spbacks = block.spbacks;
|
|
if (!spbacks) {
|
|
continue;
|
|
}
|
|
var succs = block.succs;
|
|
for (var k = 0, l = succs.length; k < l; k++) {
|
|
var s = succs[k];
|
|
if (spbacks.get(s.bid)) {
|
|
heads.set(s.dominator.bid);
|
|
}
|
|
}
|
|
}
|
|
return heads.members();
|
|
}
|
|
function LoopInfo(scc, loopId) {
|
|
var body = new BlockSet();
|
|
body.setBlocks(scc);
|
|
body.recount();
|
|
this.id = loopId;
|
|
this.body = body;
|
|
this.exit = new BlockSet();
|
|
this.save = {};
|
|
this.head = new BlockSet();
|
|
this.npreds = 0;
|
|
}
|
|
var heads = findLoopHeads(this.blocks);
|
|
if (heads.length <= 0) {
|
|
this.markedLoops = true;
|
|
return true;
|
|
}
|
|
var worklist = heads.sort(function (a, b) {
|
|
return a.level - b.level;
|
|
});
|
|
var loopId = 0;
|
|
for (var n = worklist.length - 1; n >= 0; n--) {
|
|
var top = worklist[n];
|
|
var sccs = findSCCs(top);
|
|
if (sccs.length === 0) {
|
|
continue;
|
|
}
|
|
for (var i = 0, j = sccs.length; i < j; i++) {
|
|
var scc = sccs[i];
|
|
var loop = new LoopInfo(scc, loopId++);
|
|
for (var k = 0, l = scc.length; k < l; k++) {
|
|
var h = scc[k];
|
|
if (h.level === top.level + 1 && !h.loop) {
|
|
h.loop = loop;
|
|
loop.head.set(h.bid);
|
|
var preds = h.preds;
|
|
for (var pi = 0, pj = preds.length; pi < pj; pi++) {
|
|
loop.body.get(preds[pi].bid) && h.npreds--;
|
|
}
|
|
loop.npreds += h.npreds;
|
|
}
|
|
}
|
|
for (var k = 0, l = scc.length; k < l; k++) {
|
|
var h = scc[k];
|
|
if (h.level === top.level + 1) {
|
|
h.npreds = loop.npreds;
|
|
}
|
|
}
|
|
loop.head.recount();
|
|
}
|
|
}
|
|
this.markedLoops = true;
|
|
return true;
|
|
}
|
|
};
|
|
return Analysis;
|
|
}();
|
|
(function (exports) {
|
|
var lang = exports.lang = {
|
|
Node: {},
|
|
Program: {
|
|
extends: 'Node',
|
|
fields: [
|
|
'@body'
|
|
]
|
|
},
|
|
Statement: {
|
|
extends: 'Node'
|
|
},
|
|
EmptyStatement: {
|
|
extends: 'Statement'
|
|
},
|
|
BlockStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@body'
|
|
]
|
|
},
|
|
ExpressionStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@expression'
|
|
]
|
|
},
|
|
IfStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@test',
|
|
'@consequent',
|
|
'@alternate'
|
|
]
|
|
},
|
|
LabeledStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@label',
|
|
'@body'
|
|
]
|
|
},
|
|
BreakStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@label'
|
|
]
|
|
},
|
|
ContinueStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@label'
|
|
]
|
|
},
|
|
WithStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@object',
|
|
'@body'
|
|
]
|
|
},
|
|
SwitchStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@discriminant',
|
|
'@cases',
|
|
'lexical'
|
|
]
|
|
},
|
|
ReturnStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@argument'
|
|
]
|
|
},
|
|
ThrowStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@argument'
|
|
]
|
|
},
|
|
TryStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@block',
|
|
'@handlers',
|
|
'@finalizer'
|
|
]
|
|
},
|
|
WhileStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@test',
|
|
'@body'
|
|
]
|
|
},
|
|
DoWhileStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@body',
|
|
'@test'
|
|
]
|
|
},
|
|
ForStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@init',
|
|
'@test',
|
|
'@update',
|
|
'@body'
|
|
]
|
|
},
|
|
ForInStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@left',
|
|
'@right',
|
|
'@body',
|
|
'each'
|
|
]
|
|
},
|
|
LetStatement: {
|
|
extends: 'Statement',
|
|
fields: [
|
|
'@head',
|
|
'@body'
|
|
]
|
|
},
|
|
DebuggerStatement: {
|
|
extends: 'Statement'
|
|
},
|
|
Declaration: {
|
|
extends: 'Statement'
|
|
},
|
|
FunctionDeclaration: {
|
|
extends: 'Declaration',
|
|
fields: [
|
|
'@id',
|
|
'@params',
|
|
'@body',
|
|
'@decltype',
|
|
'generator',
|
|
'expression',
|
|
'@modifiers'
|
|
]
|
|
},
|
|
VariableDeclaration: {
|
|
extends: 'Declaration',
|
|
fields: [
|
|
'kind',
|
|
'@declarations'
|
|
]
|
|
},
|
|
VariableDeclarator: {
|
|
extends: 'Node',
|
|
fields: [
|
|
'@id',
|
|
'@init',
|
|
'@decltype',
|
|
'@arguments'
|
|
]
|
|
},
|
|
Expression: {
|
|
extends: 'Pattern'
|
|
},
|
|
ThisExpression: {
|
|
extends: 'Expression'
|
|
},
|
|
ArrayExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@elements'
|
|
]
|
|
},
|
|
ObjectExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@properties'
|
|
]
|
|
},
|
|
Property: {
|
|
extends: 'Node',
|
|
fields: [
|
|
'@key',
|
|
'@value',
|
|
'kind'
|
|
]
|
|
},
|
|
FunctionExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@id',
|
|
'@params',
|
|
'@body',
|
|
'@decltype',
|
|
'generator',
|
|
'expression'
|
|
]
|
|
},
|
|
SequenceExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@expressions'
|
|
]
|
|
},
|
|
UnaryExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'operator',
|
|
'@argument',
|
|
'prefix'
|
|
]
|
|
},
|
|
BinaryExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'operator',
|
|
'@left',
|
|
'@right'
|
|
]
|
|
},
|
|
AssignmentExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@left',
|
|
'operator',
|
|
'@right'
|
|
]
|
|
},
|
|
UpdateExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'operator',
|
|
'@argument',
|
|
'prefix'
|
|
]
|
|
},
|
|
LogicalExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'operator',
|
|
'@left',
|
|
'@right'
|
|
]
|
|
},
|
|
ConditionalExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@test',
|
|
'@consequent',
|
|
'@alternate'
|
|
]
|
|
},
|
|
NewExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@callee',
|
|
'@arguments'
|
|
]
|
|
},
|
|
CallExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@callee',
|
|
'@arguments'
|
|
]
|
|
},
|
|
MemberExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@object',
|
|
'@property',
|
|
'computed',
|
|
'kind'
|
|
]
|
|
},
|
|
YieldExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@argument'
|
|
]
|
|
},
|
|
ComprehensionExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@blocks',
|
|
'@filter'
|
|
]
|
|
},
|
|
GeneratorExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@blocks',
|
|
'@filter'
|
|
]
|
|
},
|
|
LetExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@head',
|
|
'@body'
|
|
]
|
|
},
|
|
Pattern: {
|
|
extends: 'Node'
|
|
},
|
|
ObjectPattern: {
|
|
extends: 'Pattern',
|
|
fields: [
|
|
'@properties'
|
|
]
|
|
},
|
|
ArrayPattern: {
|
|
extends: 'Pattern',
|
|
fields: [
|
|
'@elements'
|
|
]
|
|
},
|
|
SwitchCase: {
|
|
extends: 'Node',
|
|
fields: [
|
|
'@test',
|
|
'@consequent'
|
|
]
|
|
},
|
|
CatchClause: {
|
|
extends: 'Node',
|
|
fields: [
|
|
'@param',
|
|
'@guard',
|
|
'@body'
|
|
]
|
|
},
|
|
Identifier: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'name',
|
|
'kind'
|
|
]
|
|
},
|
|
Literal: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'value'
|
|
]
|
|
},
|
|
Type: {
|
|
extends: 'Node'
|
|
},
|
|
PointerType: {
|
|
extends: 'Type',
|
|
fields: [
|
|
'@base'
|
|
]
|
|
},
|
|
ArrayType: {
|
|
extends: 'PointerType',
|
|
fields: [
|
|
'length'
|
|
]
|
|
},
|
|
StructType: {
|
|
extends: 'Type',
|
|
fields: [
|
|
'@id',
|
|
'@members',
|
|
'isUnion'
|
|
]
|
|
},
|
|
MemberDeclarator: {
|
|
extends: 'Node',
|
|
fields: [
|
|
'modifiers',
|
|
'@declarator'
|
|
]
|
|
},
|
|
ArrowType: {
|
|
extends: 'Type',
|
|
fields: [
|
|
'@params',
|
|
'@return'
|
|
]
|
|
},
|
|
TypeIdentifier: {
|
|
extends: 'Type',
|
|
fields: [
|
|
'name'
|
|
]
|
|
},
|
|
TypeAliasDirective: {
|
|
extends: 'Node',
|
|
fields: [
|
|
'@original',
|
|
'@alias'
|
|
]
|
|
},
|
|
CastExpression: {
|
|
extends: 'Expression',
|
|
fields: [
|
|
'@as',
|
|
'@argument'
|
|
]
|
|
}
|
|
};
|
|
function allFields(spec) {
|
|
var fields = [
|
|
'leadingComments',
|
|
'loc'
|
|
];
|
|
while (spec) {
|
|
if (spec.fields) {
|
|
fields = spec.fields.concat(fields);
|
|
}
|
|
spec = spec.extends ? lang[spec.extends] : null;
|
|
}
|
|
return fields;
|
|
}
|
|
;
|
|
exports.allFields = allFields;
|
|
function prefixUnderscore(s) {
|
|
return '_' + s;
|
|
}
|
|
function ensureConstructor(name, spec) {
|
|
if (!exports[name]) {
|
|
var fields = allFields(spec);
|
|
var children = [];
|
|
var body = [
|
|
'this.type = "' + name + '";'
|
|
];
|
|
for (var i = 0, j = fields.length; i < j; i++) {
|
|
var fname = fields[i];
|
|
if (fname.charAt(0) === '@') {
|
|
fields[i] = fname = fname.substr(1);
|
|
children.push(fname);
|
|
}
|
|
body.push('this.' + fname + ' = _' + fname + ';');
|
|
}
|
|
var node = new Function(fields.map(prefixUnderscore), body.join('\n'));
|
|
if (spec.extends) {
|
|
var pnode = ensureConstructor(spec.extends, lang[spec.extends]);
|
|
node.prototype = Object.create(pnode.prototype);
|
|
}
|
|
Object.defineProperty(node.prototype, '_children', {
|
|
value: children,
|
|
writable: true,
|
|
configurable: true,
|
|
enumerable: false
|
|
});
|
|
exports[name] = node;
|
|
}
|
|
return exports[name];
|
|
}
|
|
for (var name in lang) {
|
|
ensureConstructor(name, lang[name]);
|
|
}
|
|
exports.makePass = function makePass(name, prop) {
|
|
return function (o) {
|
|
var trans, arr;
|
|
var child, children = this._children;
|
|
for (var i = 0, j = children.length; i < j; i++) {
|
|
if (!(child = this[children[i]])) {
|
|
continue;
|
|
}
|
|
if (child instanceof Array) {
|
|
arr = this[children[i]] = [];
|
|
for (var k = 0, l = child.length; k < l; k++) {
|
|
if (!child[k]) {
|
|
arr.push(child[k]);
|
|
} else if (typeof child[k][name] === 'function') {
|
|
trans = child[k][name](o);
|
|
if (trans !== null) {
|
|
arr.push(trans);
|
|
}
|
|
}
|
|
}
|
|
} else if (typeof child[name] === 'function') {
|
|
trans = child[name](o);
|
|
if (trans === null) {
|
|
this[children[i]] = undefined;
|
|
} else {
|
|
this[children[i]] = trans;
|
|
}
|
|
}
|
|
}
|
|
if (typeof this[prop] === 'function') {
|
|
if (o.logger && typeof this.loc !== 'undefined') {
|
|
o.logger.push(this);
|
|
trans = this[prop](o);
|
|
o.logger.pop();
|
|
} else {
|
|
trans = this[prop](o);
|
|
}
|
|
if (trans === null) {
|
|
return null;
|
|
}
|
|
return trans ? trans : this;
|
|
}
|
|
return this;
|
|
};
|
|
};
|
|
exports.makePass = function makePass(name, prop, backward) {
|
|
return function (o) {
|
|
var trans, arr;
|
|
var child, children = this._children;
|
|
var i, k;
|
|
for (var x = 0, j = children.length; x < j; x++) {
|
|
i = backward ? children.length - 1 - x : x;
|
|
if (!(child = this[children[i]])) {
|
|
continue;
|
|
}
|
|
if (child instanceof Array) {
|
|
arr = this[children[i]] = [];
|
|
var y;
|
|
for (var y = 0, l = child.length; y < l; y++) {
|
|
k = backward ? child.length - 1 - y : y;
|
|
if (!child[k]) {
|
|
if (backward) {
|
|
arr.unshift(child[k]);
|
|
} else {
|
|
arr.push(child[k]);
|
|
}
|
|
} else if (typeof child[k][name] === 'function') {
|
|
trans = child[k][name](o);
|
|
if (trans !== null) {
|
|
if (backward) {
|
|
arr.unshift(trans);
|
|
} else {
|
|
arr.push(trans);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (typeof child[name] === 'function') {
|
|
trans = child[name](o);
|
|
if (trans === null) {
|
|
this[children[i]] = undefined;
|
|
} else {
|
|
this[children[i]] = trans;
|
|
}
|
|
}
|
|
}
|
|
if (typeof this[prop] === 'function') {
|
|
if (o.logger && typeof this.loc !== 'undefined') {
|
|
o.logger.push(this);
|
|
trans = this[prop](o);
|
|
o.logger.pop();
|
|
} else {
|
|
trans = this[prop](o);
|
|
}
|
|
if (trans === null) {
|
|
return null;
|
|
}
|
|
return trans ? trans : this;
|
|
}
|
|
return this;
|
|
};
|
|
};
|
|
exports.lift = function lift(raw) {
|
|
if (!raw) {
|
|
return raw;
|
|
}
|
|
if (raw instanceof Array) {
|
|
return raw.map(function (r) {
|
|
return r ? lift(r) : r;
|
|
});
|
|
}
|
|
var type = raw.type;
|
|
var Node = exports[type];
|
|
if (!Node) {
|
|
throw new Error('unknown node type `' + type + '\'');
|
|
}
|
|
var node = new Node();
|
|
node.loc = raw.loc;
|
|
var fields = allFields(lang[type]);
|
|
for (var i = 0, j = fields.length; i < j; i++) {
|
|
var field;
|
|
if (fields[i].charAt(0) === '@') {
|
|
field = fields[i].substr(1);
|
|
if (raw[field]) {
|
|
node[field] = lift(raw[field]);
|
|
}
|
|
} else {
|
|
field = fields[i];
|
|
node[field] = raw[field];
|
|
}
|
|
}
|
|
return node;
|
|
};
|
|
exports.flatten = function flatten(node) {
|
|
if (!node) {
|
|
return node;
|
|
}
|
|
if (node instanceof Array) {
|
|
return node.map(function (n) {
|
|
return flatten(n);
|
|
});
|
|
}
|
|
var type = node.type;
|
|
var raw = {
|
|
type: type
|
|
};
|
|
var fields = allFields(lang[type]);
|
|
for (var i = 0, j = fields.length; i < j; i++) {
|
|
var field;
|
|
if (fields[i].charAt(0) === '@') {
|
|
field = fields[i].substr(1);
|
|
if (node[field]) {
|
|
raw[field] = flatten(node[field]);
|
|
} else {
|
|
raw[field] = null;
|
|
}
|
|
} else {
|
|
field = fields[i];
|
|
raw[field] = node[field];
|
|
}
|
|
}
|
|
return raw;
|
|
};
|
|
}(typeof exports === 'undefined' ? estransform = {} : exports));
|
|
(function (exports) {
|
|
var Syntax, Precedence, BinaryPrecedence, Regex, VisitorKeys, VisitorOption, isArray, base, indent, json, renumber, hexadecimal, quotes, escapeless, newline, space, parentheses, semicolons, extra, parse;
|
|
Syntax = {
|
|
AssignmentExpression: 'AssignmentExpression',
|
|
ArrayExpression: 'ArrayExpression',
|
|
BlockStatement: 'BlockStatement',
|
|
BinaryExpression: 'BinaryExpression',
|
|
BreakStatement: 'BreakStatement',
|
|
CallExpression: 'CallExpression',
|
|
CatchClause: 'CatchClause',
|
|
ConditionalExpression: 'ConditionalExpression',
|
|
ContinueStatement: 'ContinueStatement',
|
|
DoWhileStatement: 'DoWhileStatement',
|
|
DebuggerStatement: 'DebuggerStatement',
|
|
EmptyStatement: 'EmptyStatement',
|
|
ExpressionStatement: 'ExpressionStatement',
|
|
ForStatement: 'ForStatement',
|
|
ForInStatement: 'ForInStatement',
|
|
FunctionDeclaration: 'FunctionDeclaration',
|
|
FunctionExpression: 'FunctionExpression',
|
|
Identifier: 'Identifier',
|
|
IfStatement: 'IfStatement',
|
|
Literal: 'Literal',
|
|
LabeledStatement: 'LabeledStatement',
|
|
LogicalExpression: 'LogicalExpression',
|
|
MemberExpression: 'MemberExpression',
|
|
NewExpression: 'NewExpression',
|
|
ObjectExpression: 'ObjectExpression',
|
|
Program: 'Program',
|
|
Property: 'Property',
|
|
ReturnStatement: 'ReturnStatement',
|
|
SequenceExpression: 'SequenceExpression',
|
|
SwitchStatement: 'SwitchStatement',
|
|
SwitchCase: 'SwitchCase',
|
|
ThisExpression: 'ThisExpression',
|
|
ThrowStatement: 'ThrowStatement',
|
|
TryStatement: 'TryStatement',
|
|
UnaryExpression: 'UnaryExpression',
|
|
UpdateExpression: 'UpdateExpression',
|
|
VariableDeclaration: 'VariableDeclaration',
|
|
VariableDeclarator: 'VariableDeclarator',
|
|
WhileStatement: 'WhileStatement',
|
|
WithStatement: 'WithStatement'
|
|
};
|
|
Precedence = {
|
|
Sequence: 0,
|
|
Assignment: 1,
|
|
Conditional: 2,
|
|
LogicalOR: 3,
|
|
LogicalAND: 4,
|
|
BitwiseOR: 5,
|
|
BitwiseXOR: 6,
|
|
BitwiseAND: 7,
|
|
Equality: 8,
|
|
Relational: 9,
|
|
BitwiseSHIFT: 10,
|
|
Additive: 11,
|
|
Multiplicative: 12,
|
|
Unary: 13,
|
|
Postfix: 14,
|
|
Call: 15,
|
|
New: 16,
|
|
Member: 17,
|
|
Primary: 18
|
|
};
|
|
BinaryPrecedence = {
|
|
'||': Precedence.LogicalOR,
|
|
'&&': Precedence.LogicalAND,
|
|
'|': Precedence.BitwiseOR,
|
|
'^': Precedence.BitwiseXOR,
|
|
'&': Precedence.BitwiseAND,
|
|
'==': Precedence.Equality,
|
|
'!=': Precedence.Equality,
|
|
'===': Precedence.Equality,
|
|
'!==': Precedence.Equality,
|
|
'<': Precedence.Relational,
|
|
'>': Precedence.Relational,
|
|
'<=': Precedence.Relational,
|
|
'>=': Precedence.Relational,
|
|
'in': Precedence.Relational,
|
|
'instanceof': Precedence.Relational,
|
|
'<<': Precedence.BitwiseSHIFT,
|
|
'>>': Precedence.BitwiseSHIFT,
|
|
'>>>': Precedence.BitwiseSHIFT,
|
|
'+': Precedence.Additive,
|
|
'-': Precedence.Additive,
|
|
'*': Precedence.Multiplicative,
|
|
'%': Precedence.Multiplicative,
|
|
'/': Precedence.Multiplicative
|
|
};
|
|
Regex = {
|
|
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]')
|
|
};
|
|
function getDefaultOptions() {
|
|
return {
|
|
indent: null,
|
|
base: null,
|
|
parse: null,
|
|
comment: false,
|
|
format: {
|
|
indent: {
|
|
style: ' ',
|
|
base: 0,
|
|
adjustMultilineComment: false
|
|
},
|
|
json: false,
|
|
renumber: false,
|
|
hexadecimal: false,
|
|
quotes: 'single',
|
|
escapeless: false,
|
|
compact: false,
|
|
parentheses: true,
|
|
semicolons: true
|
|
}
|
|
};
|
|
}
|
|
function stringToArray(str) {
|
|
var length = str.length, result = [], i;
|
|
for (i = 0; i < length; i += 1) {
|
|
result[i] = str.charAt(i);
|
|
}
|
|
return result;
|
|
}
|
|
function stringRepeat(str, num) {
|
|
var result = '';
|
|
for (num |= 0; num > 0; num >>>= 1, str += str) {
|
|
if (num & 1) {
|
|
result += str;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
isArray = Array.isArray;
|
|
if (!isArray) {
|
|
isArray = function isArray(array) {
|
|
return Object.prototype.toString.call(array) === '[object Array]';
|
|
};
|
|
}
|
|
function endsWithLineTerminator(str) {
|
|
var len, ch;
|
|
len = str.length;
|
|
ch = str.charAt(len - 1);
|
|
return ch === '\r' || ch === '\n';
|
|
}
|
|
function shallowCopy(obj) {
|
|
var ret = {}, key;
|
|
for (key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
ret[key] = obj[key];
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
function deepCopy(obj) {
|
|
var ret = {}, key, val;
|
|
for (key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
val = obj[key];
|
|
if (typeof val === 'object' && val !== null) {
|
|
ret[key] = deepCopy(val);
|
|
} else {
|
|
ret[key] = val;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
function updateDeeply(target, override) {
|
|
var key, val;
|
|
function isHashObject(target) {
|
|
return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp);
|
|
}
|
|
for (key in override) {
|
|
if (override.hasOwnProperty(key)) {
|
|
val = override[key];
|
|
if (isHashObject(val)) {
|
|
if (isHashObject(target[key])) {
|
|
updateDeeply(target[key], val);
|
|
} else {
|
|
target[key] = updateDeeply({}, val);
|
|
}
|
|
} else {
|
|
target[key] = val;
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
function generateNumber(value) {
|
|
var result, point, temp, exponent, pos;
|
|
if (value !== value) {
|
|
throw new Error('Numeric literal whose value is NaN');
|
|
}
|
|
if (1 / value < 0) {
|
|
throw new Error('Numeric literal whose value is negative');
|
|
}
|
|
if (value === 1 / 0) {
|
|
return json ? 'null' : renumber ? '1e400' : '1e+400';
|
|
}
|
|
result = '' + value;
|
|
if (!renumber || result.length < 3) {
|
|
return result;
|
|
}
|
|
point = result.indexOf('.');
|
|
if (!json && result.charAt(0) === '0' && point === 1) {
|
|
point = 0;
|
|
result = result.slice(1);
|
|
}
|
|
temp = result;
|
|
result = result.replace('e+', 'e');
|
|
exponent = 0;
|
|
if ((pos = temp.indexOf('e')) > 0) {
|
|
exponent = +temp.slice(pos + 1);
|
|
temp = temp.slice(0, pos);
|
|
}
|
|
if (point >= 0) {
|
|
exponent -= temp.length - point - 1;
|
|
temp = +(temp.slice(0, point) + temp.slice(point + 1)) + '';
|
|
}
|
|
pos = 0;
|
|
while (temp.charAt(temp.length + pos - 1) === '0') {
|
|
pos -= 1;
|
|
}
|
|
if (pos !== 0) {
|
|
exponent -= pos;
|
|
temp = temp.slice(0, pos);
|
|
}
|
|
if (exponent !== 0) {
|
|
temp += 'e' + exponent;
|
|
}
|
|
if ((temp.length < result.length || hexadecimal && value > 1000000000000 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length) && +temp === value) {
|
|
result = temp;
|
|
}
|
|
return result;
|
|
}
|
|
function escapeAllowedCharacter(ch, next) {
|
|
var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\';
|
|
switch (ch) {
|
|
case '\b':
|
|
result += 'b';
|
|
break;
|
|
case '\f':
|
|
result += 'f';
|
|
break;
|
|
case '\t':
|
|
result += 't';
|
|
break;
|
|
default:
|
|
if (json || code > 255) {
|
|
result += 'u' + '0000'.slice(hex.length) + hex;
|
|
} else if (ch === '\0' && '0123456789'.indexOf(next) < 0) {
|
|
result += '0';
|
|
} else if (ch === '\v') {
|
|
result += 'v';
|
|
} else {
|
|
result += 'x' + '00'.slice(hex.length) + hex;
|
|
}
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
function escapeDisallowedCharacter(ch) {
|
|
var result = '\\';
|
|
switch (ch) {
|
|
case '\\':
|
|
result += '\\';
|
|
break;
|
|
case '\n':
|
|
result += 'n';
|
|
break;
|
|
case '\r':
|
|
result += 'r';
|
|
break;
|
|
case '\u2028':
|
|
result += 'u2028';
|
|
break;
|
|
case '\u2029':
|
|
result += 'u2029';
|
|
break;
|
|
default:
|
|
throw new Error('Incorrectly classified character');
|
|
}
|
|
return result;
|
|
}
|
|
function escapeString(str) {
|
|
var result = '', i, len, ch, next, singleQuotes = 0, doubleQuotes = 0, single;
|
|
if (typeof str[0] === 'undefined') {
|
|
str = stringToArray(str);
|
|
}
|
|
for (i = 0, len = str.length; i < len; i += 1) {
|
|
ch = str[i];
|
|
if (ch === '\'') {
|
|
singleQuotes += 1;
|
|
} else if (ch === '"') {
|
|
doubleQuotes += 1;
|
|
} else if (ch === '/' && json) {
|
|
result += '\\';
|
|
} else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) {
|
|
result += escapeDisallowedCharacter(ch);
|
|
continue;
|
|
} else if (json && ch < ' ' || !(json || escapeless || ch >= ' ' && ch <= '~')) {
|
|
result += escapeAllowedCharacter(ch, str[i + 1]);
|
|
continue;
|
|
}
|
|
result += ch;
|
|
}
|
|
single = !(quotes === 'double' || quotes === 'auto' && doubleQuotes < singleQuotes);
|
|
str = result;
|
|
result = single ? '\'' : '"';
|
|
if (typeof str[0] === 'undefined') {
|
|
str = stringToArray(str);
|
|
}
|
|
for (i = 0, len = str.length; i < len; i += 1) {
|
|
ch = str[i];
|
|
if (ch === '\'' && single || ch === '"' && !single) {
|
|
result += '\\';
|
|
}
|
|
result += ch;
|
|
}
|
|
return result + (single ? '\'' : '"');
|
|
}
|
|
function isWhiteSpace(ch) {
|
|
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;
|
|
}
|
|
function isLineTerminator(ch) {
|
|
return '\n\r\u2028\u2029'.indexOf(ch) >= 0;
|
|
}
|
|
function isIdentifierPart(ch) {
|
|
return ch === '$' || ch === '_' || ch === '\\' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch.charCodeAt(0) >= 128 && Regex.NonAsciiIdentifierPart.test(ch);
|
|
}
|
|
function join(left, right) {
|
|
var leftChar = left.charAt(left.length - 1), rightChar = right.charAt(0);
|
|
if ((leftChar === '+' || leftChar === '-') && leftChar === rightChar || isIdentifierPart(leftChar) && isIdentifierPart(rightChar)) {
|
|
return left + ' ' + right;
|
|
} else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) {
|
|
return left + right;
|
|
}
|
|
return left + space + right;
|
|
}
|
|
function addIndent(stmt) {
|
|
return base + stmt;
|
|
}
|
|
function calculateSpaces(str) {
|
|
var i;
|
|
for (i = str.length - 1; i >= 0; i -= 1) {
|
|
if (isLineTerminator(str.charAt(i))) {
|
|
break;
|
|
}
|
|
}
|
|
return str.length - 1 - i;
|
|
}
|
|
function adjustMultilineComment(value, specialBase) {
|
|
var array, i, len, line, j, ch, spaces, previousBase;
|
|
array = value.split(/\r\n|[\r\n]/);
|
|
spaces = Number.MAX_VALUE;
|
|
for (i = 1, len = array.length; i < len; i += 1) {
|
|
line = array[i];
|
|
j = 0;
|
|
while (j < line.length && isWhiteSpace(line[j])) {
|
|
j += 1;
|
|
}
|
|
if (spaces > j) {
|
|
spaces = j;
|
|
}
|
|
}
|
|
if (typeof specialBase !== 'undefined') {
|
|
previousBase = base;
|
|
if (array[1][spaces] === '*') {
|
|
specialBase += ' ';
|
|
}
|
|
base = specialBase;
|
|
} else {
|
|
if (spaces % 2 === 1) {
|
|
spaces -= 1;
|
|
}
|
|
previousBase = base;
|
|
}
|
|
for (i = 1, len = array.length; i < len; i += 1) {
|
|
array[i] = addIndent(array[i].slice(spaces));
|
|
}
|
|
base = previousBase;
|
|
return array.join('\n');
|
|
}
|
|
function generateComment(comment, specialBase) {
|
|
if (comment.type === 'Line') {
|
|
if (endsWithLineTerminator(comment.value)) {
|
|
return '//' + comment.value;
|
|
} else {
|
|
return '//' + comment.value + '\n';
|
|
}
|
|
}
|
|
if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) {
|
|
return adjustMultilineComment('/*' + comment.value + '*/', specialBase);
|
|
}
|
|
return '/*' + comment.value + '*/';
|
|
}
|
|
function addCommentsToStatement(stmt, result) {
|
|
var i, len, comment, save, node, tailingToStatement, specialBase, fragment;
|
|
if (stmt.leadingComments) {
|
|
save = result;
|
|
comment = stmt.leadingComments[0];
|
|
result = generateComment(comment);
|
|
if (!endsWithLineTerminator(result)) {
|
|
result += '\n';
|
|
}
|
|
for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) {
|
|
comment = stmt.leadingComments[i];
|
|
fragment = generateComment(comment);
|
|
if (!endsWithLineTerminator(fragment)) {
|
|
fragment += '\n';
|
|
}
|
|
result += addIndent(fragment);
|
|
}
|
|
result += addIndent(save);
|
|
}
|
|
if (stmt.trailingComments) {
|
|
tailingToStatement = !endsWithLineTerminator(result);
|
|
specialBase = stringRepeat(' ', calculateSpaces(base + result + indent));
|
|
for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) {
|
|
comment = stmt.trailingComments[i];
|
|
if (tailingToStatement) {
|
|
if (i === 0) {
|
|
result += indent;
|
|
} else {
|
|
result += specialBase;
|
|
}
|
|
result += generateComment(comment, specialBase);
|
|
} else {
|
|
result += addIndent(generateComment(comment));
|
|
}
|
|
if (i !== len - 1 && !endsWithLineTerminator(result)) {
|
|
result += '\n';
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function parenthesize(text, current, should) {
|
|
if (current < should) {
|
|
return '(' + text + ')';
|
|
}
|
|
return text;
|
|
}
|
|
function maybeBlock(stmt, semicolonOptional) {
|
|
var previousBase, result, noLeadingComment;
|
|
noLeadingComment = !extra.comment || !stmt.leadingComments;
|
|
if (stmt.type === Syntax.BlockStatement && noLeadingComment) {
|
|
return space + generateStatement(stmt);
|
|
}
|
|
if (stmt.type === Syntax.EmptyStatement && noLeadingComment) {
|
|
return ';';
|
|
}
|
|
previousBase = base;
|
|
base += indent;
|
|
result = newline + addIndent(generateStatement(stmt, {
|
|
semicolonOptional: semicolonOptional
|
|
}));
|
|
base = previousBase;
|
|
return result;
|
|
}
|
|
function maybeBlockSuffix(stmt, result) {
|
|
if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !endsWithLineTerminator(result)) {
|
|
return space;
|
|
}
|
|
if (endsWithLineTerminator(result)) {
|
|
return addIndent('');
|
|
}
|
|
return (newline === '' ? ' ' : newline) + addIndent('');
|
|
}
|
|
function generateFunctionBody(node) {
|
|
var result, i, len;
|
|
result = '(';
|
|
for (i = 0, len = node.params.length; i < len; i += 1) {
|
|
result += node.params[i].name;
|
|
if (i + 1 < len) {
|
|
result += ',' + space;
|
|
}
|
|
}
|
|
return result + ')' + maybeBlock(node.body);
|
|
}
|
|
function generateExpression(expr, option) {
|
|
var result, precedence, currentPrecedence, previousBase, i, len, raw, fragment, allowIn, allowCall, allowUnparenthesizedNew;
|
|
precedence = option.precedence;
|
|
allowIn = option.allowIn;
|
|
allowCall = option.allowCall;
|
|
switch (expr.type) {
|
|
case Syntax.SequenceExpression:
|
|
result = '';
|
|
allowIn |= Precedence.Sequence < precedence;
|
|
for (i = 0, len = expr.expressions.length; i < len; i += 1) {
|
|
result += generateExpression(expr.expressions[i], {
|
|
precedence: Precedence.Assignment,
|
|
allowIn: allowIn,
|
|
allowCall: true
|
|
});
|
|
if (i + 1 < len) {
|
|
result += ',' + space;
|
|
}
|
|
}
|
|
result = parenthesize(result, Precedence.Sequence, precedence);
|
|
break;
|
|
case Syntax.AssignmentExpression:
|
|
allowIn |= Precedence.Assignment < precedence;
|
|
result = parenthesize(generateExpression(expr.left, {
|
|
precedence: Precedence.Call,
|
|
allowIn: allowIn,
|
|
allowCall: true
|
|
}) + space + expr.operator + space + generateExpression(expr.right, {
|
|
precedence: Precedence.Assignment,
|
|
allowIn: allowIn,
|
|
allowCall: true
|
|
}), Precedence.Assignment, precedence);
|
|
break;
|
|
case Syntax.ConditionalExpression:
|
|
allowIn |= Precedence.Conditional < precedence;
|
|
result = parenthesize(generateExpression(expr.test, {
|
|
precedence: Precedence.LogicalOR,
|
|
allowIn: allowIn,
|
|
allowCall: true
|
|
}) + space + '?' + space + generateExpression(expr.consequent, {
|
|
precedence: Precedence.Assignment,
|
|
allowIn: allowIn,
|
|
allowCall: true
|
|
}) + space + ':' + space + generateExpression(expr.alternate, {
|
|
precedence: Precedence.Assignment,
|
|
allowIn: allowIn,
|
|
allowCall: true
|
|
}), Precedence.Conditional, precedence);
|
|
break;
|
|
case Syntax.LogicalExpression:
|
|
case Syntax.BinaryExpression:
|
|
currentPrecedence = BinaryPrecedence[expr.operator];
|
|
allowIn |= currentPrecedence < precedence;
|
|
result = join(generateExpression(expr.left, {
|
|
precedence: currentPrecedence,
|
|
allowIn: allowIn,
|
|
allowCall: true
|
|
}), expr.operator);
|
|
fragment = generateExpression(expr.right, {
|
|
precedence: currentPrecedence + 1,
|
|
allowIn: allowIn,
|
|
allowCall: true
|
|
});
|
|
if (expr.operator === '/' && result.charAt(result.length - 1) === '/') {
|
|
result += ' ' + fragment;
|
|
} else {
|
|
result = join(result, fragment);
|
|
}
|
|
if (expr.operator === 'in' && !allowIn) {
|
|
result = '(' + result + ')';
|
|
} else {
|
|
result = parenthesize(result, currentPrecedence, precedence);
|
|
}
|
|
break;
|
|
case Syntax.CallExpression:
|
|
result = generateExpression(expr.callee, {
|
|
precedence: Precedence.Call,
|
|
allowIn: true,
|
|
allowCall: true,
|
|
allowUnparenthesizedNew: false
|
|
});
|
|
result += '(';
|
|
for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
|
|
result += generateExpression(expr['arguments'][i], {
|
|
precedence: Precedence.Assignment,
|
|
allowIn: true,
|
|
allowCall: true
|
|
});
|
|
if (i + 1 < len) {
|
|
result += ',' + space;
|
|
}
|
|
}
|
|
result += ')';
|
|
if (!allowCall) {
|
|
result = '(' + result + ')';
|
|
} else {
|
|
result = parenthesize(result, Precedence.Call, precedence);
|
|
}
|
|
break;
|
|
case Syntax.NewExpression:
|
|
len = expr['arguments'].length;
|
|
allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew;
|
|
result = join('new', generateExpression(expr.callee, {
|
|
precedence: Precedence.New,
|
|
allowIn: true,
|
|
allowCall: false,
|
|
allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0
|
|
}));
|
|
if (!allowUnparenthesizedNew || parentheses || len > 0) {
|
|
result += '(';
|
|
for (i = 0; i < len; i += 1) {
|
|
result += generateExpression(expr['arguments'][i], {
|
|
precedence: Precedence.Assignment,
|
|
allowIn: true,
|
|
allowCall: true
|
|
});
|
|
if (i + 1 < len) {
|
|
result += ',' + space;
|
|
}
|
|
}
|
|
result += ')';
|
|
}
|
|
result = parenthesize(result, Precedence.New, precedence);
|
|
break;
|
|
case Syntax.MemberExpression:
|
|
result = generateExpression(expr.object, {
|
|
precedence: Precedence.Call,
|
|
allowIn: true,
|
|
allowCall: allowCall,
|
|
allowUnparenthesizedNew: false
|
|
});
|
|
if (expr.computed) {
|
|
result += '[' + generateExpression(expr.property, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: allowCall
|
|
}) + ']';
|
|
} else {
|
|
if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
|
|
if (result.indexOf('.') < 0) {
|
|
if (!/[eExX]/.test(result) && !(result.length >= 2 && result[0] === '0')) {
|
|
result += '.';
|
|
}
|
|
}
|
|
}
|
|
result += '.' + expr.property.name;
|
|
}
|
|
result = parenthesize(result, Precedence.Member, precedence);
|
|
break;
|
|
case Syntax.UnaryExpression:
|
|
fragment = generateExpression(expr.argument, {
|
|
precedence: Precedence.Unary + (expr.argument.type === Syntax.UnaryExpression && expr.operator.length < 3 && expr.argument.operator === expr.operator ? 1 : 0),
|
|
allowIn: true,
|
|
allowCall: true
|
|
});
|
|
if (space === '') {
|
|
result = join(expr.operator, fragment);
|
|
} else {
|
|
result = expr.operator;
|
|
if (result.length > 2) {
|
|
result += ' ';
|
|
}
|
|
result += fragment;
|
|
}
|
|
result = parenthesize(result, Precedence.Unary, precedence);
|
|
break;
|
|
case Syntax.UpdateExpression:
|
|
if (expr.prefix) {
|
|
result = parenthesize(expr.operator + generateExpression(expr.argument, {
|
|
precedence: Precedence.Unary,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}), Precedence.Unary, precedence);
|
|
} else {
|
|
result = parenthesize(generateExpression(expr.argument, {
|
|
precedence: Precedence.Postfix,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + expr.operator, Precedence.Postfix, precedence);
|
|
}
|
|
break;
|
|
case Syntax.FunctionExpression:
|
|
result = 'function';
|
|
if (expr.id) {
|
|
result += ' ' + expr.id.name;
|
|
} else {
|
|
result += space;
|
|
}
|
|
result += generateFunctionBody(expr);
|
|
break;
|
|
case Syntax.ArrayExpression:
|
|
if (!expr.elements.length) {
|
|
result = '[]';
|
|
break;
|
|
}
|
|
result = '[' + newline;
|
|
previousBase = base;
|
|
base += indent;
|
|
for (i = 0, len = expr.elements.length; i < len; i += 1) {
|
|
if (!expr.elements[i]) {
|
|
result += addIndent('');
|
|
if (i + 1 === len) {
|
|
result += ',';
|
|
}
|
|
} else {
|
|
result += addIndent(generateExpression(expr.elements[i], {
|
|
precedence: Precedence.Assignment,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}));
|
|
}
|
|
if (i + 1 < len) {
|
|
result += ',' + newline;
|
|
}
|
|
}
|
|
base = previousBase;
|
|
if (!endsWithLineTerminator(result)) {
|
|
result += newline;
|
|
}
|
|
result += addIndent(']');
|
|
break;
|
|
case Syntax.Property:
|
|
if (expr.kind === 'get' || expr.kind === 'set') {
|
|
result = expr.kind + ' ' + generateExpression(expr.key, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + generateFunctionBody(expr.value);
|
|
} else {
|
|
result = generateExpression(expr.key, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ':' + space + generateExpression(expr.value, {
|
|
precedence: Precedence.Assignment,
|
|
allowIn: true,
|
|
allowCall: true
|
|
});
|
|
}
|
|
break;
|
|
case Syntax.ObjectExpression:
|
|
if (!expr.properties.length) {
|
|
result = '{}';
|
|
break;
|
|
}
|
|
result = '{' + newline;
|
|
previousBase = base;
|
|
base += indent;
|
|
for (i = 0, len = expr.properties.length; i < len; i += 1) {
|
|
result += addIndent(generateExpression(expr.properties[i], {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}));
|
|
if (i + 1 < len) {
|
|
result += ',' + newline;
|
|
}
|
|
}
|
|
base = previousBase;
|
|
if (!endsWithLineTerminator(result)) {
|
|
result += newline;
|
|
}
|
|
result += addIndent('}');
|
|
break;
|
|
case Syntax.ThisExpression:
|
|
result = 'this';
|
|
break;
|
|
case Syntax.Identifier:
|
|
result = expr.name;
|
|
break;
|
|
case Syntax.Literal:
|
|
if (expr.hasOwnProperty('raw') && parse) {
|
|
try {
|
|
raw = parse(expr.raw).body[0].expression;
|
|
if (raw.type === Syntax.Literal) {
|
|
if (raw.value === expr.value) {
|
|
result = expr.raw;
|
|
break;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
}
|
|
}
|
|
if (expr.value === null) {
|
|
result = 'null';
|
|
break;
|
|
}
|
|
if (typeof expr.value === 'string') {
|
|
result = escapeString(expr.value);
|
|
break;
|
|
}
|
|
if (typeof expr.value === 'number') {
|
|
result = generateNumber(expr.value);
|
|
break;
|
|
}
|
|
result = expr.value.toString();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (result === undefined) {
|
|
throw new Error('Unknown expression type: ' + expr.type);
|
|
}
|
|
return result;
|
|
}
|
|
function generateStatement(stmt, option) {
|
|
var i, len, result, previousBase, node, allowIn, fragment, semicolon;
|
|
allowIn = true;
|
|
semicolon = ';';
|
|
if (option) {
|
|
allowIn = option.allowIn === undefined || option.allowIn;
|
|
if (!semicolons && option.semicolonOptional === true) {
|
|
semicolon = '';
|
|
}
|
|
}
|
|
switch (stmt.type) {
|
|
case Syntax.BlockStatement:
|
|
result = '{' + newline;
|
|
previousBase = base;
|
|
base += indent;
|
|
for (i = 0, len = stmt.body.length; i < len; i += 1) {
|
|
fragment = addIndent(generateStatement(stmt.body[i], {
|
|
semicolonOptional: i === len - 1
|
|
}));
|
|
result += fragment;
|
|
if (!endsWithLineTerminator(fragment)) {
|
|
result += newline;
|
|
}
|
|
}
|
|
base = previousBase;
|
|
result += addIndent('}');
|
|
break;
|
|
case Syntax.BreakStatement:
|
|
if (stmt.label) {
|
|
result = 'break ' + stmt.label.name + semicolon;
|
|
} else {
|
|
result = 'break' + semicolon;
|
|
}
|
|
break;
|
|
case Syntax.ContinueStatement:
|
|
if (stmt.label) {
|
|
result = 'continue ' + stmt.label.name + semicolon;
|
|
} else {
|
|
result = 'continue' + semicolon;
|
|
}
|
|
break;
|
|
case Syntax.DoWhileStatement:
|
|
result = join('do', maybeBlock(stmt.body));
|
|
result += maybeBlockSuffix(stmt.body, result);
|
|
result += 'while' + space + '(' + generateExpression(stmt.test, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ')' + semicolon;
|
|
break;
|
|
case Syntax.CatchClause:
|
|
previousBase = base;
|
|
base += indent;
|
|
result = 'catch' + space + '(' + generateExpression(stmt.param, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ')';
|
|
base = previousBase;
|
|
result += maybeBlock(stmt.body);
|
|
break;
|
|
case Syntax.DebuggerStatement:
|
|
result = 'debugger' + semicolon;
|
|
break;
|
|
case Syntax.EmptyStatement:
|
|
result = ';';
|
|
break;
|
|
case Syntax.ExpressionStatement:
|
|
result = generateExpression(stmt.expression, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
});
|
|
if (result.charAt(0) === '{' || result.slice(0, 8) === 'function' && ' ('.indexOf(result.charAt(8)) >= 0) {
|
|
result = '(' + result + ')' + semicolon;
|
|
} else {
|
|
result += semicolon;
|
|
}
|
|
break;
|
|
case Syntax.VariableDeclarator:
|
|
if (stmt.init) {
|
|
result = stmt.id.name + space + '=' + space + generateExpression(stmt.init, {
|
|
precedence: Precedence.Assignment,
|
|
allowIn: allowIn,
|
|
allowCall: true
|
|
});
|
|
} else {
|
|
result = stmt.id.name;
|
|
}
|
|
break;
|
|
case Syntax.VariableDeclaration:
|
|
result = stmt.kind;
|
|
if (stmt.declarations.length === 1 && stmt.declarations[0].init && stmt.declarations[0].init.type === Syntax.FunctionExpression) {
|
|
result += ' ' + generateStatement(stmt.declarations[0], {
|
|
allowIn: allowIn
|
|
});
|
|
} else {
|
|
previousBase = base;
|
|
base += indent;
|
|
node = stmt.declarations[0];
|
|
if (extra.comment && node.leadingComments) {
|
|
result += '\n' + addIndent(generateStatement(node, {
|
|
allowIn: allowIn
|
|
}));
|
|
} else {
|
|
result += ' ' + generateStatement(node, {
|
|
allowIn: allowIn
|
|
});
|
|
}
|
|
for (i = 1, len = stmt.declarations.length; i < len; i += 1) {
|
|
node = stmt.declarations[i];
|
|
if (extra.comment && node.leadingComments) {
|
|
result += ',' + newline + addIndent(generateStatement(node, {
|
|
allowIn: allowIn
|
|
}));
|
|
} else {
|
|
result += ',' + space + generateStatement(node, {
|
|
allowIn: allowIn
|
|
});
|
|
}
|
|
}
|
|
base = previousBase;
|
|
}
|
|
result += semicolon;
|
|
break;
|
|
case Syntax.ThrowStatement:
|
|
result = join('throw', generateExpression(stmt.argument, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
})) + semicolon;
|
|
break;
|
|
case Syntax.TryStatement:
|
|
result = 'try' + maybeBlock(stmt.block);
|
|
result += maybeBlockSuffix(stmt.block, result);
|
|
for (i = 0, len = stmt.handlers.length; i < len; i += 1) {
|
|
result += generateStatement(stmt.handlers[i]);
|
|
if (stmt.finalizer || i + 1 !== len) {
|
|
result += maybeBlockSuffix(stmt.handlers[i].body, result);
|
|
}
|
|
}
|
|
if (stmt.finalizer) {
|
|
result += 'finally' + maybeBlock(stmt.finalizer);
|
|
}
|
|
break;
|
|
case Syntax.SwitchStatement:
|
|
previousBase = base;
|
|
base += indent;
|
|
result = 'switch' + space + '(' + generateExpression(stmt.discriminant, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ')' + space + '{' + newline;
|
|
base = previousBase;
|
|
if (stmt.cases) {
|
|
for (i = 0, len = stmt.cases.length; i < len; i += 1) {
|
|
fragment = addIndent(generateStatement(stmt.cases[i], {
|
|
semicolonOptional: i === len - 1
|
|
}));
|
|
result += fragment;
|
|
if (!endsWithLineTerminator(fragment)) {
|
|
result += newline;
|
|
}
|
|
}
|
|
}
|
|
result += addIndent('}');
|
|
break;
|
|
case Syntax.SwitchCase:
|
|
previousBase = base;
|
|
base += indent;
|
|
if (stmt.test) {
|
|
result = join('case', generateExpression(stmt.test, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
})) + ':';
|
|
} else {
|
|
result = 'default:';
|
|
}
|
|
i = 0;
|
|
len = stmt.consequent.length;
|
|
if (len && stmt.consequent[0].type === Syntax.BlockStatement) {
|
|
fragment = maybeBlock(stmt.consequent[0]);
|
|
result += fragment;
|
|
i = 1;
|
|
}
|
|
if (i !== len && !endsWithLineTerminator(result)) {
|
|
result += newline;
|
|
}
|
|
for (; i < len; i += 1) {
|
|
fragment = addIndent(generateStatement(stmt.consequent[i], {
|
|
semicolonOptional: i === len - 1 && semicolon === ''
|
|
}));
|
|
result += fragment;
|
|
if (i + 1 !== len && !endsWithLineTerminator(fragment)) {
|
|
result += newline;
|
|
}
|
|
}
|
|
base = previousBase;
|
|
break;
|
|
case Syntax.IfStatement:
|
|
previousBase = base;
|
|
base += indent;
|
|
if (stmt.alternate) {
|
|
if (stmt.alternate.type === Syntax.IfStatement) {
|
|
result = 'if' + space + '(' + generateExpression(stmt.test, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ')';
|
|
base = previousBase;
|
|
result += maybeBlock(stmt.consequent);
|
|
result += maybeBlockSuffix(stmt.consequent, result);
|
|
result += 'else ' + generateStatement(stmt.alternate);
|
|
} else {
|
|
result = 'if' + space + '(' + generateExpression(stmt.test, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ')';
|
|
base = previousBase;
|
|
result += maybeBlock(stmt.consequent);
|
|
result += maybeBlockSuffix(stmt.consequent, result);
|
|
result += 'else';
|
|
result = join(result, maybeBlock(stmt.alternate, semicolon === ''));
|
|
}
|
|
} else {
|
|
result = 'if' + space + '(' + generateExpression(stmt.test, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ')';
|
|
base = previousBase;
|
|
result += maybeBlock(stmt.consequent, semicolon === '');
|
|
}
|
|
break;
|
|
case Syntax.ForStatement:
|
|
previousBase = base;
|
|
base += indent;
|
|
result = 'for' + space + '(';
|
|
if (stmt.init) {
|
|
if (stmt.init.type === Syntax.VariableDeclaration) {
|
|
result += generateStatement(stmt.init, {
|
|
allowIn: false
|
|
});
|
|
} else {
|
|
result += generateExpression(stmt.init, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: false,
|
|
allowCall: true
|
|
}) + ';';
|
|
}
|
|
} else {
|
|
result += ';';
|
|
}
|
|
if (stmt.test) {
|
|
result += space + generateExpression(stmt.test, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ';';
|
|
} else {
|
|
result += ';';
|
|
}
|
|
if (stmt.update) {
|
|
result += space + generateExpression(stmt.update, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ')';
|
|
} else {
|
|
result += ')';
|
|
}
|
|
base = previousBase;
|
|
result += maybeBlock(stmt.body, semicolon === '');
|
|
break;
|
|
case Syntax.ForInStatement:
|
|
result = 'for' + space + '(';
|
|
if (stmt.left.type === Syntax.VariableDeclaration) {
|
|
previousBase = base;
|
|
base += indent + indent;
|
|
result += stmt.left.kind + ' ' + generateStatement(stmt.left.declarations[0], {
|
|
allowIn: false
|
|
});
|
|
base = previousBase;
|
|
} else {
|
|
previousBase = base;
|
|
base += indent;
|
|
result += generateExpression(stmt.left, {
|
|
precedence: Precedence.Call,
|
|
allowIn: true,
|
|
allowCall: true
|
|
});
|
|
base = previousBase;
|
|
}
|
|
previousBase = base;
|
|
base += indent;
|
|
result = join(result, 'in');
|
|
result = join(result, generateExpression(stmt.right, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
})) + ')';
|
|
base = previousBase;
|
|
result += maybeBlock(stmt.body, semicolon === '');
|
|
break;
|
|
case Syntax.LabeledStatement:
|
|
result = stmt.label.name + ':' + maybeBlock(stmt.body, semicolon === '');
|
|
break;
|
|
case Syntax.Program:
|
|
result = '';
|
|
for (i = 0, len = stmt.body.length; i < len; i += 1) {
|
|
fragment = addIndent(generateStatement(stmt.body[i], {
|
|
semicolonOptional: i === len - 1
|
|
}));
|
|
result += fragment;
|
|
if (i + 1 < len && !endsWithLineTerminator(fragment)) {
|
|
result += newline;
|
|
}
|
|
}
|
|
break;
|
|
case Syntax.FunctionDeclaration:
|
|
result = 'function' + space;
|
|
if (stmt.id) {
|
|
result += (space === '' ? ' ' : '') + stmt.id.name;
|
|
}
|
|
result += generateFunctionBody(stmt);
|
|
break;
|
|
case Syntax.ReturnStatement:
|
|
if (stmt.argument) {
|
|
result = join('return', generateExpression(stmt.argument, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
})) + semicolon;
|
|
} else {
|
|
result = 'return' + semicolon;
|
|
}
|
|
break;
|
|
case Syntax.WhileStatement:
|
|
previousBase = base;
|
|
base += indent;
|
|
result = 'while' + space + '(' + generateExpression(stmt.test, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ')';
|
|
base = previousBase;
|
|
result += maybeBlock(stmt.body, semicolon === '');
|
|
break;
|
|
case Syntax.WithStatement:
|
|
previousBase = base;
|
|
base += indent;
|
|
result = 'with' + space + '(' + generateExpression(stmt.object, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
}) + ')';
|
|
base = previousBase;
|
|
result += maybeBlock(stmt.body, semicolon === '');
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (result === undefined) {
|
|
throw new Error('Unknown statement type: ' + stmt.type);
|
|
}
|
|
if (extra.comment) {
|
|
return addCommentsToStatement(stmt, result);
|
|
}
|
|
return result;
|
|
}
|
|
function generate(node, options) {
|
|
var defaultOptions = getDefaultOptions();
|
|
if (typeof options !== 'undefined') {
|
|
if (typeof options.indent === 'string') {
|
|
defaultOptions.format.indent.style = options.indent;
|
|
}
|
|
if (typeof options.base === 'number') {
|
|
defaultOptions.format.indent.base = options.base;
|
|
}
|
|
options = updateDeeply(defaultOptions, options);
|
|
indent = options.format.indent.style;
|
|
if (typeof options.base === 'string') {
|
|
base = options.base;
|
|
} else {
|
|
base = stringRepeat(indent, options.format.indent.base);
|
|
}
|
|
} else {
|
|
options = defaultOptions;
|
|
indent = options.format.indent.style;
|
|
base = stringRepeat(indent, options.format.indent.base);
|
|
}
|
|
json = options.format.json;
|
|
renumber = options.format.renumber;
|
|
hexadecimal = json ? false : options.format.hexadecimal;
|
|
quotes = json ? 'double' : options.format.quotes;
|
|
escapeless = options.format.escapeless;
|
|
if (options.format.compact) {
|
|
newline = space = indent = base = '';
|
|
} else {
|
|
newline = '\n';
|
|
space = ' ';
|
|
}
|
|
parentheses = options.format.parentheses;
|
|
semicolons = options.format.semicolons;
|
|
parse = json ? null : options.parse;
|
|
extra = options;
|
|
switch (node.type) {
|
|
case Syntax.BlockStatement:
|
|
case Syntax.BreakStatement:
|
|
case Syntax.CatchClause:
|
|
case Syntax.ContinueStatement:
|
|
case Syntax.DoWhileStatement:
|
|
case Syntax.DebuggerStatement:
|
|
case Syntax.EmptyStatement:
|
|
case Syntax.ExpressionStatement:
|
|
case Syntax.ForStatement:
|
|
case Syntax.ForInStatement:
|
|
case Syntax.FunctionDeclaration:
|
|
case Syntax.IfStatement:
|
|
case Syntax.LabeledStatement:
|
|
case Syntax.Program:
|
|
case Syntax.ReturnStatement:
|
|
case Syntax.SwitchStatement:
|
|
case Syntax.SwitchCase:
|
|
case Syntax.ThrowStatement:
|
|
case Syntax.TryStatement:
|
|
case Syntax.VariableDeclaration:
|
|
case Syntax.VariableDeclarator:
|
|
case Syntax.WhileStatement:
|
|
case Syntax.WithStatement:
|
|
return generateStatement(node);
|
|
case Syntax.AssignmentExpression:
|
|
case Syntax.ArrayExpression:
|
|
case Syntax.BinaryExpression:
|
|
case Syntax.CallExpression:
|
|
case Syntax.ConditionalExpression:
|
|
case Syntax.FunctionExpression:
|
|
case Syntax.Identifier:
|
|
case Syntax.Literal:
|
|
case Syntax.LogicalExpression:
|
|
case Syntax.MemberExpression:
|
|
case Syntax.NewExpression:
|
|
case Syntax.ObjectExpression:
|
|
case Syntax.Property:
|
|
case Syntax.SequenceExpression:
|
|
case Syntax.ThisExpression:
|
|
case Syntax.UnaryExpression:
|
|
case Syntax.UpdateExpression:
|
|
return generateExpression(node, {
|
|
precedence: Precedence.Sequence,
|
|
allowIn: true,
|
|
allowCall: true
|
|
});
|
|
default:
|
|
break;
|
|
}
|
|
throw new Error('Unknown node type: ' + node.type);
|
|
}
|
|
VisitorKeys = {
|
|
AssignmentExpression: [
|
|
'left',
|
|
'right'
|
|
],
|
|
ArrayExpression: [
|
|
'elements'
|
|
],
|
|
BlockStatement: [
|
|
'body'
|
|
],
|
|
BinaryExpression: [
|
|
'left',
|
|
'right'
|
|
],
|
|
BreakStatement: [
|
|
'label'
|
|
],
|
|
CallExpression: [
|
|
'callee',
|
|
'arguments'
|
|
],
|
|
CatchClause: [
|
|
'param',
|
|
'body'
|
|
],
|
|
ConditionalExpression: [
|
|
'test',
|
|
'consequent',
|
|
'alternate'
|
|
],
|
|
ContinueStatement: [
|
|
'label'
|
|
],
|
|
DoWhileStatement: [
|
|
'body',
|
|
'test'
|
|
],
|
|
DebuggerStatement: [],
|
|
EmptyStatement: [],
|
|
ExpressionStatement: [
|
|
'expression'
|
|
],
|
|
ForStatement: [
|
|
'init',
|
|
'test',
|
|
'update',
|
|
'body'
|
|
],
|
|
ForInStatement: [
|
|
'left',
|
|
'right',
|
|
'body'
|
|
],
|
|
FunctionDeclaration: [
|
|
'id',
|
|
'params',
|
|
'body'
|
|
],
|
|
FunctionExpression: [
|
|
'id',
|
|
'params',
|
|
'body'
|
|
],
|
|
Identifier: [],
|
|
IfStatement: [
|
|
'test',
|
|
'consequent',
|
|
'alternate'
|
|
],
|
|
Literal: [],
|
|
LabeledStatement: [
|
|
'label',
|
|
'body'
|
|
],
|
|
LogicalExpression: [
|
|
'left',
|
|
'right'
|
|
],
|
|
MemberExpression: [
|
|
'object',
|
|
'property'
|
|
],
|
|
NewExpression: [
|
|
'callee',
|
|
'arguments'
|
|
],
|
|
ObjectExpression: [
|
|
'properties'
|
|
],
|
|
Program: [
|
|
'body'
|
|
],
|
|
Property: [
|
|
'key',
|
|
'value'
|
|
],
|
|
ReturnStatement: [
|
|
'argument'
|
|
],
|
|
SequenceExpression: [
|
|
'expressions'
|
|
],
|
|
SwitchStatement: [
|
|
'descriminant',
|
|
'cases'
|
|
],
|
|
SwitchCase: [
|
|
'test',
|
|
'consequent'
|
|
],
|
|
ThisExpression: [],
|
|
ThrowStatement: [
|
|
'argument'
|
|
],
|
|
TryStatement: [
|
|
'block',
|
|
'handlers',
|
|
'finalizer'
|
|
],
|
|
UnaryExpression: [
|
|
'argument'
|
|
],
|
|
UpdateExpression: [
|
|
'argument'
|
|
],
|
|
VariableDeclaration: [
|
|
'declarations'
|
|
],
|
|
VariableDeclarator: [
|
|
'id',
|
|
'init'
|
|
],
|
|
WhileStatement: [
|
|
'test',
|
|
'body'
|
|
],
|
|
WithStatement: [
|
|
'object',
|
|
'body'
|
|
],
|
|
PointerType: [
|
|
'base'
|
|
],
|
|
StructType: [
|
|
'id',
|
|
'fields'
|
|
],
|
|
FieldDeclarator: [
|
|
'id',
|
|
'decltype'
|
|
],
|
|
ArrowType: [
|
|
'params',
|
|
'return'
|
|
],
|
|
TypeIdentifier: [],
|
|
TypeAliasDirective: [
|
|
'original',
|
|
'alias'
|
|
],
|
|
CastExpression: [
|
|
'as',
|
|
'argument'
|
|
]
|
|
};
|
|
VisitorOption = {
|
|
Break: 1,
|
|
Skip: 2
|
|
};
|
|
function traverse(top, visitor) {
|
|
var worklist, leavelist, node, ret, current, current2, candidates, candidate;
|
|
worklist = [
|
|
top
|
|
];
|
|
leavelist = [];
|
|
while (worklist.length) {
|
|
node = worklist.pop();
|
|
if (node) {
|
|
if (visitor.enter) {
|
|
ret = visitor.enter(node);
|
|
} else {
|
|
ret = undefined;
|
|
}
|
|
if (ret === VisitorOption.Break) {
|
|
return;
|
|
}
|
|
worklist.push(null);
|
|
leavelist.push(node);
|
|
if (ret !== VisitorOption.Skip) {
|
|
candidates = VisitorKeys[node.type];
|
|
current = candidates.length;
|
|
while ((current -= 1) >= 0) {
|
|
candidate = node[candidates[current]];
|
|
if (candidate) {
|
|
if (isArray(candidate)) {
|
|
current2 = candidate.length;
|
|
while ((current2 -= 1) >= 0) {
|
|
if (candidate[current2]) {
|
|
worklist.push(candidate[current2]);
|
|
}
|
|
}
|
|
} else {
|
|
worklist.push(candidate);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
node = leavelist.pop();
|
|
if (visitor.leave) {
|
|
ret = visitor.leave(node);
|
|
} else {
|
|
ret = undefined;
|
|
}
|
|
if (ret === VisitorOption.Break) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function upperBound(array, func) {
|
|
var diff, len, i, current;
|
|
len = array.length;
|
|
i = 0;
|
|
while (len) {
|
|
diff = len >>> 1;
|
|
current = i + diff;
|
|
if (func(array[current])) {
|
|
len = diff;
|
|
} else {
|
|
i = current + 1;
|
|
len -= diff + 1;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
function lowerBound(array, func) {
|
|
var diff, len, i, current;
|
|
len = array.length;
|
|
i = 0;
|
|
while (len) {
|
|
diff = len >>> 1;
|
|
current = i + diff;
|
|
if (func(array[current])) {
|
|
i = current + 1;
|
|
len -= diff + 1;
|
|
} else {
|
|
len = diff;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
function extendCommentRange(comment, tokens) {
|
|
var target, token;
|
|
target = upperBound(tokens, function search(token) {
|
|
return token.range[0] > comment.range[0];
|
|
});
|
|
comment.extendedRange = [
|
|
comment.range[0],
|
|
comment.range[1]
|
|
];
|
|
if (target !== tokens.length) {
|
|
comment.extendedRange[1] = tokens[target].range[0];
|
|
}
|
|
target -= 1;
|
|
if (target >= 0) {
|
|
if (target < tokens.length) {
|
|
comment.extendedRange[0] = tokens[target].range[1];
|
|
} else if (token.length) {
|
|
comment.extendedRange[1] = tokens[tokens.length - 1].range[0];
|
|
}
|
|
}
|
|
return comment;
|
|
}
|
|
function attachComments(tree, providedComments, tokens) {
|
|
var comments = [], comment, len, i;
|
|
if (!tree.range) {
|
|
throw new Error('attachComments needs range information');
|
|
}
|
|
if (!tokens.length) {
|
|
if (providedComments.length) {
|
|
for (i = 0, len = providedComments.length; i < len; i += 1) {
|
|
comment = deepCopy(providedComments[i]);
|
|
comment.extendedRange = [
|
|
0,
|
|
tree.range[0]
|
|
];
|
|
comments.push(comment);
|
|
}
|
|
tree.leadingComments = comments;
|
|
}
|
|
return tree;
|
|
}
|
|
for (i = 0, len = providedComments.length; i < len; i += 1) {
|
|
comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens));
|
|
}
|
|
traverse(tree, {
|
|
cursor: 0,
|
|
enter: function (node) {
|
|
var comment;
|
|
while (this.cursor < comments.length) {
|
|
comment = comments[this.cursor];
|
|
if (comment.extendedRange[1] > node.range[0]) {
|
|
break;
|
|
}
|
|
if (comment.extendedRange[1] === node.range[0]) {
|
|
if (!node.leadingComments) {
|
|
node.leadingComments = [];
|
|
}
|
|
node.leadingComments.push(comment);
|
|
comments.splice(this.cursor, 1);
|
|
} else {
|
|
this.cursor += 1;
|
|
}
|
|
}
|
|
if (this.cursor === comments.length) {
|
|
return VisitorOption.Break;
|
|
}
|
|
if (comments[this.cursor].extendedRange[0] > node.range[1]) {
|
|
return VisitorOption.Skip;
|
|
}
|
|
}
|
|
});
|
|
traverse(tree, {
|
|
cursor: 0,
|
|
leave: function (node) {
|
|
var comment;
|
|
while (this.cursor < comments.length) {
|
|
comment = comments[this.cursor];
|
|
if (node.range[1] < comment.extendedRange[0]) {
|
|
break;
|
|
}
|
|
if (node.range[1] === comment.extendedRange[0]) {
|
|
if (!node.trailingComments) {
|
|
node.trailingComments = [];
|
|
}
|
|
node.trailingComments.push(comment);
|
|
comments.splice(this.cursor, 1);
|
|
} else {
|
|
this.cursor += 1;
|
|
}
|
|
}
|
|
if (this.cursor === comments.length) {
|
|
return VisitorOption.Break;
|
|
}
|
|
if (comments[this.cursor].extendedRange[0] > node.range[1]) {
|
|
return VisitorOption.Skip;
|
|
}
|
|
}
|
|
});
|
|
return tree;
|
|
}
|
|
exports.version = '0.0.6-dev';
|
|
exports.generate = generate;
|
|
exports.traverse = traverse;
|
|
exports.attachComments = attachComments;
|
|
}(typeof exports === 'undefined' ? escodegen = {} : exports));
|
|
var verifierOptions = systemOptions.register(new OptionSet('Verifier Options'));
|
|
var verifierTraceLevel = verifierOptions.register(new Option('tv', 'tv', 'number', 0, 'Verifier Trace Level'));
|
|
var Type = function () {
|
|
function type() {
|
|
unexpected('Type is Abstract');
|
|
}
|
|
type.prototype.equals = function (other) {
|
|
return this === other;
|
|
};
|
|
type.prototype.merge = function (other) {
|
|
unexpected('Merging ' + this + ' with ' + other);
|
|
};
|
|
type.cache = {
|
|
name: {},
|
|
classInfo: [],
|
|
instanceInfo: [],
|
|
scriptInfo: [],
|
|
methodInfo: []
|
|
};
|
|
type.from = function from(x, domain) {
|
|
var traitsTypeCache = null;
|
|
if (x instanceof ClassInfo) {
|
|
traitsTypeCache = type.cache.classInfo;
|
|
} else if (x instanceof InstanceInfo) {
|
|
traitsTypeCache = type.cache.instanceInfo;
|
|
} else if (x instanceof ScriptInfo) {
|
|
traitsTypeCache = type.cache.scriptInfo;
|
|
}
|
|
if (traitsTypeCache) {
|
|
return traitsTypeCache[x.runtimeId] || (traitsTypeCache[x.runtimeId] = new TraitsType(x, domain));
|
|
}
|
|
if (x instanceof ActivationInfo) {
|
|
return new TraitsType(x.methodInfo);
|
|
} else if (x instanceof Global) {
|
|
return new TraitsType(x.scriptInfo);
|
|
} else if (x instanceof Interface) {
|
|
return new TraitsType(x.classInfo, domain);
|
|
} else if (x instanceof MethodInfo) {
|
|
return new MethodType(x);
|
|
} else if (domain && x instanceof Class) {
|
|
return type.from(x.classInfo, domain);
|
|
}
|
|
return Type.Any;
|
|
};
|
|
type.fromSimpleName = function (name, domain) {
|
|
return Type.fromName(Multiname.fromSimpleName(name), domain);
|
|
};
|
|
type.fromName = function fromName(mn, domain) {
|
|
if (mn === undefined) {
|
|
return Type.Undefined;
|
|
} else {
|
|
var qn = Multiname.isQName(mn) ? Multiname.getFullQualifiedName(mn) : undefined;
|
|
if (qn) {
|
|
var ty = type.cache.name[qn];
|
|
if (ty) {
|
|
return ty;
|
|
}
|
|
}
|
|
if (qn === Multiname.getPublicQualifiedName('void')) {
|
|
return Type.Void;
|
|
}
|
|
true;
|
|
ty = domain.findClassInfo(mn);
|
|
ty = ty ? type.from(ty, domain) : Type.Any;
|
|
if (mn.hasTypeParameter()) {
|
|
ty = new ParameterizedType(ty, type.fromName(mn.typeParameter, domain));
|
|
}
|
|
return type.cache.name[qn] = ty;
|
|
}
|
|
};
|
|
type.prototype.applyType = function (parameter) {
|
|
return new ParameterizedType(this, parameter);
|
|
};
|
|
type.prototype.toString = function () {
|
|
return '[type]';
|
|
};
|
|
type.prototype.isNumeric = function () {
|
|
return this === Type.Int || this === Type.Uint || this === Type.Number;
|
|
};
|
|
type.prototype.isString = function () {
|
|
return this === Type.String;
|
|
};
|
|
type.prototype.isDirectlyReadable = function () {
|
|
return this === Type.Array;
|
|
};
|
|
type.prototype.isIndexedReadable = function () {
|
|
return this.isParameterizedType();
|
|
};
|
|
type.prototype.isDirectlyWriteable = function () {
|
|
return this === Type.Array;
|
|
};
|
|
type.prototype.isIndexedWriteable = function () {
|
|
return this.isParameterizedType();
|
|
};
|
|
type.prototype.isVector = function () {
|
|
return this.isParameterizedType();
|
|
};
|
|
type.prototype.isNotDirectlyIndexable = function () {
|
|
return this === Type.Any || this === Type.XML || this === Type.XMLList || this === Type.Dictionary;
|
|
};
|
|
type.prototype.isParameterizedType = function () {
|
|
return this instanceof ParameterizedType;
|
|
};
|
|
type.prototype.instanceType = function () {
|
|
return this;
|
|
};
|
|
type.prototype.getTrait = function () {
|
|
return null;
|
|
};
|
|
type.prototype.super = function () {
|
|
unexpected('Can\'t call super on ' + this);
|
|
};
|
|
type.prototype.isSubtypeOf = function (other) {
|
|
if (this === other || this.equals(other)) {
|
|
return true;
|
|
}
|
|
return this.merge(other) === this;
|
|
};
|
|
var typesInitialized = false;
|
|
type.initializeTypes = function (domain) {
|
|
if (typesInitialized) {
|
|
return;
|
|
}
|
|
type.Any = new AtomType('Any');
|
|
type.Null = new AtomType('Null');
|
|
type.Undefined = new AtomType('Undefined');
|
|
type.Void = new AtomType('Void');
|
|
type.Int = Type.fromSimpleName('int', domain).instanceType();
|
|
type.Uint = Type.fromSimpleName('uint', domain).instanceType();
|
|
type.Class = Type.fromSimpleName('Class', domain).instanceType();
|
|
type.Array = Type.fromSimpleName('Array', domain).instanceType();
|
|
type.Object = Type.fromSimpleName('Object', domain).instanceType();
|
|
type.String = Type.fromSimpleName('String', domain).instanceType();
|
|
type.Number = Type.fromSimpleName('Number', domain).instanceType();
|
|
type.Boolean = Type.fromSimpleName('Boolean', domain).instanceType();
|
|
type.Function = Type.fromSimpleName('Function', domain).instanceType();
|
|
type.XML = Type.fromSimpleName('XML', domain).instanceType();
|
|
type.XMLList = Type.fromSimpleName('XMLList', domain).instanceType();
|
|
type.Dictionary = Type.fromSimpleName('flash.utils.Dictionary', domain).instanceType();
|
|
typesInitialized = true;
|
|
};
|
|
return type;
|
|
}();
|
|
var AtomType = function () {
|
|
function atomType(name) {
|
|
this.name = name;
|
|
}
|
|
atomType.prototype = Object.create(Type.prototype);
|
|
atomType.prototype.toString = function () {
|
|
if (this === Type.Any) {
|
|
return '?';
|
|
} else if (this === Type.Undefined) {
|
|
return '_';
|
|
} else if (this === Type.Null) {
|
|
return 'X';
|
|
} else if (this === Type.Void) {
|
|
return 'V';
|
|
}
|
|
unexpected();
|
|
};
|
|
atomType.prototype.merge = function merge(other) {
|
|
if (other instanceof TraitsType) {
|
|
return Type.Any;
|
|
}
|
|
if (this === other) {
|
|
return this;
|
|
}
|
|
if (this === Type.Any || other === Type.Any) {
|
|
return Type.Any;
|
|
}
|
|
return Type.Any;
|
|
};
|
|
return atomType;
|
|
}();
|
|
var MethodType = function () {
|
|
function methodType(methodInfo) {
|
|
this.methodInfo = methodInfo;
|
|
}
|
|
methodType.prototype = Object.create(Type.prototype);
|
|
methodType.prototype.toString = function () {
|
|
return 'MT ' + this.methodInfo;
|
|
};
|
|
return methodType;
|
|
}();
|
|
var TraitsType = function () {
|
|
function traitsType(object, domain) {
|
|
true;
|
|
this.object = object;
|
|
this.traits = object.traits;
|
|
this.domain = domain;
|
|
if (this.object instanceof InstanceInfo) {
|
|
true;
|
|
}
|
|
}
|
|
traitsType.prototype = Object.create(Type.prototype);
|
|
function nameOf(x) {
|
|
if (x instanceof ScriptInfo) {
|
|
return 'SI';
|
|
} else if (x instanceof ClassInfo) {
|
|
return 'CI:' + x.instanceInfo.name.name;
|
|
} else if (x instanceof InstanceInfo) {
|
|
return 'II:' + x.name.name;
|
|
} else if (x instanceof MethodInfo) {
|
|
return 'MI';
|
|
} else if (x instanceof ActivationInfo) {
|
|
return 'AC';
|
|
}
|
|
true;
|
|
}
|
|
function findTraitBySlotId(traits, slotId) {
|
|
for (var i = traits.length - 1; i >= 0; i--) {
|
|
if (traits[i].slotId === slotId) {
|
|
return traits[i];
|
|
}
|
|
}
|
|
unexpected('Cannot find trait with slotId: ' + slotId + ' in ' + traits);
|
|
}
|
|
function findTraitByName(traits, mn, isSetter) {
|
|
var isGetter = !isSetter;
|
|
var trait;
|
|
if (!Multiname.isQName(mn)) {
|
|
if (mn instanceof MultinameType) {
|
|
return;
|
|
}
|
|
true;
|
|
var dy;
|
|
for (var i = 0, j = mn.namespaces.length; i < j; i++) {
|
|
var qn = mn.getQName(i);
|
|
if (mn.namespaces[i].isDynamic()) {
|
|
dy = qn;
|
|
} else {
|
|
if (trait = findTraitByName(traits, qn, isSetter)) {
|
|
return trait;
|
|
}
|
|
}
|
|
}
|
|
if (dy) {
|
|
return findTraitByName(traits, dy, isSetter);
|
|
}
|
|
} else {
|
|
var qn = Multiname.getQualifiedName(mn);
|
|
for (var i = 0, j = traits.length; i < j; i++) {
|
|
trait = traits[i];
|
|
if (Multiname.getQualifiedName(trait.name) === qn) {
|
|
if (isSetter && trait.isGetter() || isGetter && trait.isSetter()) {
|
|
continue;
|
|
}
|
|
return trait;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
traitsType.prototype.getTrait = function (mn, isSetter, followSuperType) {
|
|
if (mn instanceof MultinameType) {
|
|
return null;
|
|
}
|
|
if (mn.isAttribute()) {
|
|
return null;
|
|
}
|
|
if (followSuperType && (this.isInstanceInfo() || this.isClassInfo())) {
|
|
var that = this;
|
|
do {
|
|
var trait = that.getTrait(mn, isSetter, false);
|
|
if (!trait) {
|
|
that = that.super();
|
|
}
|
|
} while (!trait && that);
|
|
return trait;
|
|
} else {
|
|
return findTraitByName(this.traits, mn, isSetter);
|
|
}
|
|
};
|
|
traitsType.prototype.getTraitAt = function (i) {
|
|
if (this.object instanceof ScriptInfo || this.object instanceof MethodInfo) {
|
|
return findTraitBySlotId(this.traits, i);
|
|
}
|
|
};
|
|
traitsType.prototype.toString = function () {
|
|
switch (this) {
|
|
case Type.Int:
|
|
return 'I';
|
|
case Type.Uint:
|
|
return 'U';
|
|
case Type.Array:
|
|
return 'A';
|
|
case Type.Object:
|
|
return 'O';
|
|
case Type.String:
|
|
return 'S';
|
|
case Type.Number:
|
|
return 'N';
|
|
case Type.Boolean:
|
|
return 'B';
|
|
case Type.Function:
|
|
return 'F';
|
|
}
|
|
return nameOf(this.object);
|
|
};
|
|
traitsType.prototype.instanceType = function () {
|
|
true;
|
|
return this.instanceCache || (this.instanceCache = Type.from(this.object.instanceInfo, this.domain));
|
|
};
|
|
traitsType.prototype.classType = function () {
|
|
true;
|
|
return this.instanceCache || (this.instanceCache = Type.from(this.object.classInfo, this.domain));
|
|
};
|
|
traitsType.prototype.super = function () {
|
|
if (this.object instanceof ClassInfo) {
|
|
return Type.Class;
|
|
}
|
|
true;
|
|
if (this.object.superName) {
|
|
var result = Type.fromName(this.object.superName, this.domain).instanceType();
|
|
true;
|
|
return result;
|
|
}
|
|
return null;
|
|
};
|
|
traitsType.prototype.isScriptInfo = function () {
|
|
return this.object instanceof ScriptInfo;
|
|
};
|
|
traitsType.prototype.isClassInfo = function () {
|
|
return this.object instanceof ClassInfo;
|
|
};
|
|
traitsType.prototype.isInstanceInfo = function () {
|
|
return this.object instanceof InstanceInfo;
|
|
};
|
|
traitsType.prototype.isInstanceOrClassInfo = function () {
|
|
return this.isInstanceInfo() || this.isClassInfo();
|
|
};
|
|
traitsType.prototype.equals = function (other) {
|
|
return this.traits === other.traits;
|
|
};
|
|
traitsType.prototype.merge = function (other) {
|
|
if (other instanceof TraitsType) {
|
|
if (this.equals(other)) {
|
|
return this;
|
|
}
|
|
if (this.isNumeric() && other.isNumeric()) {
|
|
return Type.Number;
|
|
}
|
|
if (this.isInstanceInfo() && other.isInstanceInfo()) {
|
|
var path = [];
|
|
for (var curr = this; curr; curr = curr.super()) {
|
|
path.push(curr);
|
|
}
|
|
for (var curr = other; curr; curr = curr.super()) {
|
|
for (var i = 0; i < path.length; i++) {
|
|
if (path[i].equals(curr)) {
|
|
return curr;
|
|
}
|
|
}
|
|
}
|
|
return Type.Object;
|
|
}
|
|
}
|
|
return Type.Any;
|
|
};
|
|
return traitsType;
|
|
}();
|
|
var MultinameType = function () {
|
|
function multinameType(namespaces, name, flags) {
|
|
this.namespaces = namespaces;
|
|
this.name = name;
|
|
this.flags = flags;
|
|
}
|
|
multinameType.prototype = Object.create(Type.prototype);
|
|
multinameType.prototype.toString = function () {
|
|
return 'MN';
|
|
};
|
|
return multinameType;
|
|
}();
|
|
var ParameterizedType = function () {
|
|
function parameterizedType(type, parameter) {
|
|
this.type = type;
|
|
this.parameter = parameter;
|
|
}
|
|
parameterizedType.prototype = Object.create(Type.prototype);
|
|
parameterizedType.prototype.toString = function () {
|
|
return this.type + '<' + this.parameter + '>';
|
|
};
|
|
parameterizedType.prototype.instanceType = function () {
|
|
true;
|
|
return new ParameterizedType(this.type.instanceType(), this.parameter.instanceType());
|
|
};
|
|
parameterizedType.prototype.equals = function (other) {
|
|
if (other instanceof ParameterizedType) {
|
|
return this.type.equals(other.type) && this.parameter.equals(other.parameter);
|
|
}
|
|
return false;
|
|
};
|
|
parameterizedType.prototype.merge = function (other) {
|
|
if (other instanceof TraitsType) {
|
|
if (this.equals(other)) {
|
|
return this;
|
|
}
|
|
}
|
|
return Type.Any;
|
|
};
|
|
return parameterizedType;
|
|
}();
|
|
var TypeInformation = function () {
|
|
function typeInformation() {
|
|
}
|
|
typeInformation.prototype.toString = function () {
|
|
return toKeyValueArray(this).map(function (x) {
|
|
return x[0] + ': ' + x[1];
|
|
}).join(' | ');
|
|
};
|
|
return typeInformation;
|
|
}();
|
|
var Verifier = function () {
|
|
function VerifierError(message) {
|
|
this.name = 'VerifierError';
|
|
this.message = message || '';
|
|
}
|
|
var State = function () {
|
|
var id = 0;
|
|
function state() {
|
|
this.id = id += 1;
|
|
this.stack = [];
|
|
this.scope = [];
|
|
this.local = [];
|
|
}
|
|
state.prototype.clone = function clone() {
|
|
var s = new State();
|
|
s.originalId = this.id;
|
|
s.stack = this.stack.slice(0);
|
|
s.scope = this.scope.slice(0);
|
|
s.local = this.local.slice(0);
|
|
return s;
|
|
};
|
|
state.prototype.trace = function trace(writer) {
|
|
writer.writeLn(this.toString());
|
|
};
|
|
state.prototype.toString = function () {
|
|
return '<' + this.id + (this.originalId ? ':' + this.originalId : '') + ', L[' + this.local.join(', ') + ']' + ', S[' + this.stack.join(', ') + ']' + ', $[' + this.scope.join(', ') + ']>';
|
|
};
|
|
state.prototype.equals = function (other) {
|
|
return arrayEquals(this.stack, other.stack) && arrayEquals(this.scope, other.scope) && arrayEquals(this.local, other.local);
|
|
};
|
|
function arrayEquals(a, b) {
|
|
if (a.length != b.length) {
|
|
return false;
|
|
}
|
|
for (var i = a.length - 1; i >= 0; i--) {
|
|
if (!a[i].equals(b[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
state.prototype.isSubset = function (other) {
|
|
return arraySubset(this.stack, other.stack) && arraySubset(this.scope, other.scope) && arraySubset(this.local, other.local);
|
|
};
|
|
function arraySubset(a, b) {
|
|
if (a.length != b.length) {
|
|
return false;
|
|
}
|
|
for (var i = a.length - 1; i >= 0; i--) {
|
|
if (a[i] === b[i] || a[i].equals(b[i])) {
|
|
continue;
|
|
}
|
|
if (a[i].merge(b[i]) !== a[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
state.prototype.merge = function (other) {
|
|
mergeArrays(this.local, other.local);
|
|
mergeArrays(this.stack, other.stack);
|
|
mergeArrays(this.scope, other.scope);
|
|
};
|
|
function mergeArrays(a, b) {
|
|
true;
|
|
for (var i = a.length - 1; i >= 0; i--) {
|
|
true;
|
|
if (a[i] === b[i]) {
|
|
continue;
|
|
}
|
|
a[i] = a[i].merge(b[i]);
|
|
}
|
|
}
|
|
return state;
|
|
}();
|
|
var Verification = function () {
|
|
function verification(methodInfo, domain, savedScope) {
|
|
this.savedScope = savedScope;
|
|
this.methodInfo = methodInfo;
|
|
this.domain = domain;
|
|
this.writer = new IndentingWriter();
|
|
this.returnType = Type.Undefined;
|
|
}
|
|
verification.prototype.verify = function verify() {
|
|
var mi = this.methodInfo;
|
|
var writer = verifierTraceLevel.value ? this.writer : null;
|
|
var blocks = mi.analysis.blocks;
|
|
blocks.forEach(function (x) {
|
|
x.entryState = x.exitState = null;
|
|
});
|
|
if (writer) {
|
|
this.methodInfo.trace(writer);
|
|
}
|
|
var entryState = new State();
|
|
true;
|
|
this.thisType = mi.holder ? Type.from(mi.holder, this.domain) : Type.Any;
|
|
entryState.local.push(this.thisType);
|
|
for (var i = 0; i < mi.parameters.length; i++) {
|
|
entryState.local.push(Type.fromName(mi.parameters[i].type, this.domain).instanceType());
|
|
}
|
|
var remainingLocals = mi.localCount - mi.parameters.length - 1;
|
|
if (mi.needsRest() || mi.needsArguments()) {
|
|
entryState.local.push(Type.Array);
|
|
remainingLocals -= 1;
|
|
}
|
|
for (var i = 0; i < remainingLocals; i++) {
|
|
entryState.local.push(Type.Undefined);
|
|
}
|
|
true;
|
|
if (writer) {
|
|
entryState.trace(writer);
|
|
}
|
|
for (var bi = 0, len = blocks.length; bi < len; bi++) {
|
|
blocks[bi].bdo = bi;
|
|
}
|
|
var worklist = new Shumway.SortedList(function compare(blockA, blockB) {
|
|
return blockA.bdo - blockB.bdo;
|
|
});
|
|
blocks[0].entryState = entryState;
|
|
worklist.push(blocks[0]);
|
|
while (!worklist.isEmpty()) {
|
|
var block = worklist.pop();
|
|
var exitState = block.exitState = block.entryState.clone();
|
|
this.verifyBlock(block, exitState);
|
|
block.succs.forEach(function (successor) {
|
|
if (worklist.contains(successor)) {
|
|
if (writer) {
|
|
writer.writeLn('Forward Merged Block: ' + successor.bid + ' ' + exitState.toString() + ' with ' + successor.entryState.toString());
|
|
}
|
|
successor.entryState.merge(exitState);
|
|
if (writer) {
|
|
writer.writeLn('Merged State: ' + successor.entryState);
|
|
}
|
|
return;
|
|
}
|
|
if (successor.entryState) {
|
|
if (!successor.entryState.isSubset(exitState)) {
|
|
if (writer) {
|
|
writer.writeLn('Backward Merged Block: ' + block.bid + ' with ' + successor.bid + ' ' + exitState.toString() + ' with ' + successor.entryState.toString());
|
|
}
|
|
successor.entryState.merge(exitState);
|
|
worklist.push(successor);
|
|
if (writer) {
|
|
writer.writeLn('Merged State: ' + successor.entryState);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
successor.entryState = exitState.clone();
|
|
worklist.push(successor);
|
|
if (writer) {
|
|
writer.writeLn('Added Block: ' + successor.bid + ' to worklist: ' + successor.entryState.toString());
|
|
}
|
|
});
|
|
}
|
|
if (writer) {
|
|
writer.writeLn('Inferred return type: ' + this.returnType);
|
|
}
|
|
this.methodInfo.inferredReturnType = this.returnType;
|
|
};
|
|
verification.prototype.verifyBlock = function verifyBlock(block, state) {
|
|
var savedScope = this.savedScope;
|
|
var globalScope = savedScope[0];
|
|
var local = state.local;
|
|
var stack = state.stack;
|
|
var scope = state.scope;
|
|
var writer = verifierTraceLevel.value ? this.writer : null;
|
|
var bytecodes = this.methodInfo.analysis.bytecodes;
|
|
var domain = this.domain;
|
|
var multinames = this.methodInfo.abc.constantPool.multinames;
|
|
var mi = this.methodInfo;
|
|
var bc, obj, fn, mn, l, r, val, type, returnType;
|
|
if (writer) {
|
|
writer.enter('verifyBlock: ' + block.bid + ', range: [' + block.position + ', ' + block.end.position + '], entryState: ' + state.toString() + ' {');
|
|
}
|
|
function construct(obj) {
|
|
if (obj instanceof TraitsType || obj instanceof ParameterizedType) {
|
|
if (obj === Type.Function || obj === Type.Class || obj === Type.Object) {
|
|
return Type.Object;
|
|
}
|
|
return obj.instanceType();
|
|
} else {
|
|
return Type.Any;
|
|
}
|
|
}
|
|
function ti() {
|
|
return bc.ti || (bc.ti = new TypeInformation());
|
|
}
|
|
function push(x) {
|
|
true;
|
|
ti().type = x;
|
|
stack.push(x);
|
|
}
|
|
function pop() {
|
|
return stack.pop();
|
|
}
|
|
function findProperty(mn, strict) {
|
|
if (mn instanceof MultinameType) {
|
|
if (mn.name === 'Array') {
|
|
debugger;
|
|
}
|
|
return Type.Any;
|
|
}
|
|
for (var i = scope.length - 1; i >= -savedScope.length; i--) {
|
|
var s = i >= 0 ? scope[i] : savedScope[savedScope.length + i];
|
|
if (s instanceof TraitsType) {
|
|
var trait = s.getTrait(mn, false, true);
|
|
if (trait) {
|
|
ti().scopeDepth = scope.length - i - 1;
|
|
if (s.isClassInfo() || s.isScriptInfo()) {
|
|
ti().object = LazyInitializer.create(s.object);
|
|
}
|
|
return s;
|
|
}
|
|
} else {
|
|
if (mn.name === 'Array') {
|
|
debugger;
|
|
}
|
|
return Type.Any;
|
|
}
|
|
}
|
|
var resolved = domain.findDefiningScript(mn, false);
|
|
if (resolved) {
|
|
ti().object = LazyInitializer.create(resolved.script);
|
|
return Type.from(resolved.script, domain);
|
|
}
|
|
if (mn.name === 'Array') {
|
|
debugger;
|
|
}
|
|
return Type.Any;
|
|
}
|
|
function popMultiname() {
|
|
var mn = multinames[bc.index];
|
|
if (mn.isRuntime()) {
|
|
var namespaces = mn.namespaces;
|
|
var name = mn.name;
|
|
if (mn.isRuntimeName()) {
|
|
name = pop();
|
|
}
|
|
if (mn.isRuntimeNamespace()) {
|
|
namespaces = [
|
|
pop()
|
|
];
|
|
}
|
|
return new MultinameType(namespaces, name, mn.flags);
|
|
}
|
|
return mn;
|
|
}
|
|
function accessSlot(obj) {
|
|
if (obj instanceof TraitsType) {
|
|
var trait = obj.getTraitAt(bc.index);
|
|
writer && writer.debugLn('accessSlot() -> ' + trait);
|
|
if (trait) {
|
|
ti().trait = trait;
|
|
if (trait.isSlot()) {
|
|
return Type.fromName(trait.typeName, domain).instanceType();
|
|
} else if (trait.isClass()) {
|
|
return Type.from(trait.classInfo, domain);
|
|
}
|
|
}
|
|
}
|
|
return Type.Any;
|
|
}
|
|
function isNumericMultiname(mn) {
|
|
return mn instanceof Multiname && Multiname.isNumeric(mn) || mn instanceof MultinameType && (mn.name instanceof TraitsType && mn.name.isNumeric());
|
|
}
|
|
function getProperty(obj, mn) {
|
|
if (obj instanceof TraitsType || obj instanceof ParameterizedType) {
|
|
var trait = obj.getTrait(mn, false, true);
|
|
writer && writer.debugLn('getProperty(' + mn + ') -> ' + trait);
|
|
if (trait) {
|
|
ti().trait = trait;
|
|
if (trait.isSlot() || trait.isConst()) {
|
|
return Type.fromName(trait.typeName, domain).instanceType();
|
|
} else if (trait.isGetter()) {
|
|
return Type.fromName(trait.methodInfo.returnType, domain).instanceType();
|
|
} else if (trait.isClass()) {
|
|
return Type.from(trait.classInfo, domain);
|
|
} else if (trait.isMethod()) {
|
|
return Type.from(trait.methodInfo, domain);
|
|
}
|
|
} else if (obj.isDirectlyReadable() && mn instanceof Multiname) {
|
|
ti().propertyQName = Multiname.getPublicQualifiedName(mn.name);
|
|
}
|
|
if (isNumericMultiname(mn)) {
|
|
if (obj.isIndexedReadable()) {
|
|
ti().isIndexedReadable = true;
|
|
if (obj.isVector()) {
|
|
return obj.parameter;
|
|
}
|
|
} else if (obj.isDirectlyReadable()) {
|
|
ti().isDirectlyReadable = true;
|
|
}
|
|
}
|
|
}
|
|
return Type.Any;
|
|
}
|
|
function setProperty(obj, mn, value) {
|
|
if (obj instanceof TraitsType || obj instanceof ParameterizedType) {
|
|
var trait = obj.getTrait(mn, true, true);
|
|
writer && writer.debugLn('setProperty(' + mn + ') -> ' + trait);
|
|
if (trait) {
|
|
ti().trait = trait;
|
|
} else if (obj.isDirectlyWriteable() && mn instanceof Multiname) {
|
|
ti().propertyQName = Multiname.getPublicQualifiedName(mn.name);
|
|
}
|
|
if (isNumericMultiname(mn)) {
|
|
if (obj.isDirectlyWriteable()) {
|
|
ti().isDirectlyWriteable = true;
|
|
} else if (obj.isVector()) {
|
|
ti().isIndexedWriteable = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (var bci = block.position, end = block.end.position; bci <= end; bci++) {
|
|
bc = bytecodes[bci];
|
|
var op = bc.op;
|
|
if (writer && verifierTraceLevel.value > 1) {
|
|
writer.writeLn(('stateBefore: ' + state.toString() + ' $$[' + savedScope.join(', ') + ']').padRight(' ', 100) + ' : ' + bci + ', ' + bc.toString(mi.abc));
|
|
}
|
|
switch (op) {
|
|
case 1:
|
|
break;
|
|
case 3:
|
|
pop();
|
|
break;
|
|
case 4:
|
|
mn = popMultiname();
|
|
obj = pop();
|
|
true;
|
|
ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object);
|
|
push(getProperty(obj.super(), mn));
|
|
break;
|
|
case 5:
|
|
val = pop();
|
|
mn = popMultiname();
|
|
obj = pop();
|
|
true;
|
|
ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object);
|
|
setProperty(obj.super(), mn, val);
|
|
break;
|
|
case 6:
|
|
notImplemented(bc);
|
|
break;
|
|
case 7:
|
|
notImplemented(bc);
|
|
break;
|
|
case 8:
|
|
state.local[bc.index] = Type.Undefined;
|
|
break;
|
|
case 10:
|
|
notImplemented(bc);
|
|
break;
|
|
case 11:
|
|
notImplemented(bc);
|
|
break;
|
|
case 12:
|
|
case 24:
|
|
case 13:
|
|
case 23:
|
|
case 14:
|
|
case 22:
|
|
case 15:
|
|
case 21:
|
|
case 19:
|
|
case 20:
|
|
case 25:
|
|
case 26:
|
|
pop();
|
|
pop();
|
|
break;
|
|
case 16:
|
|
break;
|
|
case 17:
|
|
case 18:
|
|
pop();
|
|
break;
|
|
case 27:
|
|
pop(Type.Int);
|
|
break;
|
|
case 29:
|
|
scope.pop();
|
|
break;
|
|
case 30:
|
|
case 35:
|
|
pop(Type.Int);
|
|
pop();
|
|
push(Type.Any);
|
|
break;
|
|
case 31:
|
|
push(Type.Boolean);
|
|
break;
|
|
case 50:
|
|
push(Type.Boolean);
|
|
break;
|
|
case 32:
|
|
push(Type.Null);
|
|
break;
|
|
case 33:
|
|
push(Type.Undefined);
|
|
break;
|
|
case 34:
|
|
notImplemented(bc);
|
|
break;
|
|
case 36:
|
|
push(Type.Int);
|
|
break;
|
|
case 37:
|
|
push(Type.Int);
|
|
break;
|
|
case 44:
|
|
push(Type.String);
|
|
break;
|
|
case 45:
|
|
push(Type.Int);
|
|
break;
|
|
case 46:
|
|
push(Type.Uint);
|
|
break;
|
|
case 47:
|
|
push(Type.Number);
|
|
break;
|
|
case 38:
|
|
push(Type.Boolean);
|
|
break;
|
|
case 39:
|
|
push(Type.Boolean);
|
|
break;
|
|
case 40:
|
|
push(Type.Number);
|
|
break;
|
|
case 41:
|
|
pop();
|
|
break;
|
|
case 42:
|
|
val = pop();
|
|
push(val);
|
|
push(val);
|
|
break;
|
|
case 43:
|
|
l = pop();
|
|
r = pop();
|
|
push(l);
|
|
push(r);
|
|
break;
|
|
case 28:
|
|
pop();
|
|
scope.push(Type.Any);
|
|
break;
|
|
case 48:
|
|
scope.push(pop());
|
|
break;
|
|
case 49:
|
|
notImplemented(bc);
|
|
break;
|
|
case 53:
|
|
case 54:
|
|
case 55:
|
|
push(Type.Int);
|
|
break;
|
|
case 56:
|
|
case 57:
|
|
push(Type.Number);
|
|
break;
|
|
case 58:
|
|
case 59:
|
|
case 60:
|
|
pop(Type.Int);
|
|
break;
|
|
case 61:
|
|
case 62:
|
|
pop(Type.Number);
|
|
break;
|
|
case 64:
|
|
push(Type.Function);
|
|
break;
|
|
case 65:
|
|
stack.popMany(bc.argCount);
|
|
obj = pop();
|
|
fn = pop();
|
|
push(Type.Any);
|
|
break;
|
|
case 67:
|
|
throw new VerifierError('callmethod');
|
|
case 68:
|
|
notImplemented(bc);
|
|
break;
|
|
case 69:
|
|
case 78:
|
|
case 79:
|
|
case 70:
|
|
case 76:
|
|
stack.popMany(bc.argCount);
|
|
mn = popMultiname();
|
|
obj = pop();
|
|
if (op === OP_callsuper || op === OP_callsupervoid) {
|
|
obj = this.thisType.super();
|
|
ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object);
|
|
}
|
|
type = getProperty(obj, mn);
|
|
if (op === OP_callpropvoid || op === OP_callsupervoid) {
|
|
break;
|
|
}
|
|
if (type instanceof MethodType) {
|
|
returnType = Type.fromName(type.methodInfo.returnType, domain).instanceType();
|
|
} else if (type instanceof TraitsType && type.isClassInfo()) {
|
|
returnType = type.instanceType();
|
|
} else {
|
|
returnType = Type.Any;
|
|
}
|
|
push(returnType);
|
|
break;
|
|
case 71:
|
|
this.returnType.merge(Type.Undefined);
|
|
break;
|
|
case 72:
|
|
type = pop();
|
|
if (mi.returnType) {
|
|
var coerceType = Type.fromName(mi.returnType, this.domain).instanceType();
|
|
if (coerceType.isSubtypeOf(type)) {
|
|
ti().noCoercionNeeded = true;
|
|
}
|
|
}
|
|
break;
|
|
case 73:
|
|
stack.popMany(bc.argCount);
|
|
stack.pop();
|
|
if (this.thisType.isInstanceInfo() && this.thisType.super() === Type.Object) {
|
|
ti().noCallSuperNeeded = true;
|
|
} else {
|
|
ti().baseClass = LazyInitializer.create(this.thisType.super().classType().object);
|
|
}
|
|
break;
|
|
case 66:
|
|
stack.popMany(bc.argCount);
|
|
push(construct(pop()));
|
|
break;
|
|
case 74:
|
|
stack.popMany(bc.argCount);
|
|
mn = popMultiname();
|
|
push(construct(getProperty(stack.pop(), mn)));
|
|
break;
|
|
case 75:
|
|
notImplemented(bc);
|
|
break;
|
|
case 77:
|
|
notImplemented(bc);
|
|
break;
|
|
case 80:
|
|
case 81:
|
|
case 82:
|
|
break;
|
|
case 83:
|
|
true;
|
|
val = pop();
|
|
obj = pop();
|
|
if (obj === Type.Any) {
|
|
push(Type.Any);
|
|
} else {
|
|
push(obj.applyType(val));
|
|
}
|
|
break;
|
|
case 84:
|
|
notImplemented(bc);
|
|
break;
|
|
case 85:
|
|
stack.popMany(bc.argCount * 2);
|
|
push(Type.Object);
|
|
break;
|
|
case 86:
|
|
stack.popMany(bc.argCount);
|
|
push(Type.Array);
|
|
break;
|
|
case 87:
|
|
push(Type.from(new ActivationInfo(this.methodInfo)));
|
|
break;
|
|
case 88:
|
|
push(Type.Any);
|
|
break;
|
|
case 89:
|
|
popMultiname();
|
|
pop();
|
|
push(Type.XMLList);
|
|
break;
|
|
case 90:
|
|
push(Type.Any);
|
|
break;
|
|
case 93:
|
|
push(findProperty(popMultiname(), true));
|
|
break;
|
|
case 94:
|
|
push(findProperty(popMultiname(), false));
|
|
break;
|
|
case 95:
|
|
notImplemented(bc);
|
|
break;
|
|
case 96:
|
|
mn = popMultiname();
|
|
push(getProperty(findProperty(mn, true), mn));
|
|
break;
|
|
case 104:
|
|
case 97:
|
|
val = pop();
|
|
mn = popMultiname();
|
|
obj = pop();
|
|
setProperty(obj, mn, val, bc);
|
|
break;
|
|
case 98:
|
|
push(local[bc.index]);
|
|
break;
|
|
case 99:
|
|
local[bc.index] = pop();
|
|
break;
|
|
case 100:
|
|
push(globalScope);
|
|
ti().object = LazyInitializer.create(globalScope.object);
|
|
break;
|
|
case 101:
|
|
push(scope[bc.index]);
|
|
break;
|
|
case 102:
|
|
mn = popMultiname();
|
|
obj = pop();
|
|
push(getProperty(obj, mn));
|
|
break;
|
|
case 103:
|
|
notImplemented(bc);
|
|
break;
|
|
case 105:
|
|
notImplemented(bc);
|
|
break;
|
|
case 106:
|
|
popMultiname();
|
|
pop();
|
|
push(Type.Boolean);
|
|
break;
|
|
case 107:
|
|
notImplemented(bc);
|
|
break;
|
|
case 108:
|
|
push(accessSlot(pop()));
|
|
break;
|
|
case 109:
|
|
val = pop();
|
|
obj = pop();
|
|
accessSlot(obj);
|
|
break;
|
|
case 110:
|
|
notImplemented(bc);
|
|
break;
|
|
case 111:
|
|
notImplemented(bc);
|
|
break;
|
|
case 112:
|
|
pop();
|
|
push(Type.String);
|
|
break;
|
|
case 113:
|
|
pop();
|
|
push(Type.String);
|
|
break;
|
|
case 114:
|
|
pop();
|
|
push(Type.String);
|
|
break;
|
|
case 131:
|
|
case 115:
|
|
pop();
|
|
push(Type.Int);
|
|
break;
|
|
case 136:
|
|
case 116:
|
|
pop();
|
|
push(Type.Uint);
|
|
break;
|
|
case 132:
|
|
case 117:
|
|
pop();
|
|
push(Type.Number);
|
|
break;
|
|
case 129:
|
|
case 118:
|
|
pop();
|
|
push(Type.Boolean);
|
|
break;
|
|
case 119:
|
|
notImplemented(bc);
|
|
break;
|
|
case 120:
|
|
break;
|
|
case 121:
|
|
pop();
|
|
push(Type.Number);
|
|
break;
|
|
case 122:
|
|
notImplemented(bc);
|
|
break;
|
|
case 123:
|
|
notImplemented(bc);
|
|
break;
|
|
case 128:
|
|
type = pop();
|
|
var coerceType = Type.fromName(multinames[bc.index], this.domain).instanceType();
|
|
if (coerceType.isSubtypeOf(type)) {
|
|
ti().noCoercionNeeded = true;
|
|
}
|
|
push(coerceType);
|
|
break;
|
|
case 130:
|
|
break;
|
|
case 133:
|
|
pop();
|
|
push(Type.String);
|
|
break;
|
|
case 134:
|
|
notImplemented(bc);
|
|
break;
|
|
case 135:
|
|
type = pop();
|
|
pop();
|
|
if (type instanceof TraitsType) {
|
|
push(type.instanceType());
|
|
} else {
|
|
push(Type.Any);
|
|
}
|
|
break;
|
|
case 137:
|
|
notImplemented(bc);
|
|
break;
|
|
case 144:
|
|
case 145:
|
|
case 147:
|
|
pop();
|
|
push(Type.Number);
|
|
break;
|
|
case 146:
|
|
case 148:
|
|
local[bc.index] = Type.Number;
|
|
break;
|
|
case 149:
|
|
pop();
|
|
push(Type.String);
|
|
break;
|
|
case 150:
|
|
pop();
|
|
push(Type.Boolean);
|
|
break;
|
|
case 160:
|
|
r = pop();
|
|
l = pop();
|
|
if (l.isNumeric() && r.isNumeric()) {
|
|
push(Type.Number);
|
|
} else if (l === Type.String || r === Type.String) {
|
|
push(Type.String);
|
|
} else {
|
|
push(Type.Any);
|
|
}
|
|
break;
|
|
case 161:
|
|
case 162:
|
|
case 163:
|
|
case 164:
|
|
pop();
|
|
pop();
|
|
push(Type.Number);
|
|
break;
|
|
case 168:
|
|
case 169:
|
|
case 170:
|
|
case 165:
|
|
case 166:
|
|
case 167:
|
|
pop();
|
|
pop();
|
|
push(Type.Int);
|
|
break;
|
|
case 151:
|
|
pop();
|
|
push(Type.Int);
|
|
break;
|
|
case 171:
|
|
case 172:
|
|
case 173:
|
|
case 174:
|
|
case 175:
|
|
case 176:
|
|
case 177:
|
|
case 180:
|
|
pop();
|
|
pop();
|
|
push(Type.Boolean);
|
|
break;
|
|
case 178:
|
|
pop();
|
|
push(Type.Boolean);
|
|
break;
|
|
case 179:
|
|
pop();
|
|
pop();
|
|
push(Type.Boolean);
|
|
break;
|
|
case 194:
|
|
case 195:
|
|
local[bc.index] = Type.Int;
|
|
break;
|
|
case 193:
|
|
case 192:
|
|
case 196:
|
|
pop();
|
|
push(Type.Int);
|
|
break;
|
|
case 197:
|
|
case 198:
|
|
case 199:
|
|
pop();
|
|
pop();
|
|
push(Type.Int);
|
|
break;
|
|
case 208:
|
|
case 209:
|
|
case 210:
|
|
case 211:
|
|
push(local[op - OP_getlocal0]);
|
|
break;
|
|
case 212:
|
|
case 213:
|
|
case 214:
|
|
case 215:
|
|
local[op - OP_setlocal0] = pop();
|
|
break;
|
|
case 239:
|
|
break;
|
|
case 240:
|
|
break;
|
|
case 241:
|
|
break;
|
|
case 242:
|
|
break;
|
|
case 243:
|
|
break;
|
|
default:
|
|
console.info('Not Implemented: ' + bc);
|
|
}
|
|
if (writer) {
|
|
if (bc.ti) {
|
|
writer.debugLn('> TI: ' + bc.ti);
|
|
}
|
|
}
|
|
}
|
|
if (writer) {
|
|
writer.leave('}');
|
|
writer.writeLn('verifiedBlock: ' + block.bid + ', range: [' + block.position + ', ' + block.end.position + '], exitState: ' + state.toString());
|
|
}
|
|
};
|
|
return verification;
|
|
}();
|
|
function verifier() {
|
|
this.writer = new IndentingWriter();
|
|
}
|
|
verifier.prototype.verifyMethod = function (methodInfo, scope) {
|
|
try {
|
|
var domain = methodInfo.abc.applicationDomain;
|
|
var scopeObjects = scope.getScopeObjects();
|
|
if (!scopeObjects[scopeObjects.length - 1]) {
|
|
if (methodInfo.holder instanceof InstanceInfo) {
|
|
scopeObjects[scopeObjects.length - 1] = methodInfo.holder.classInfo;
|
|
} else if (methodInfo.holder instanceof ClassInfo) {
|
|
scopeObjects[scopeObjects.length - 1] = methodInfo.holder;
|
|
}
|
|
}
|
|
var savedScope = scopeObjects.map(function (object) {
|
|
if (object instanceof MethodInfo) {
|
|
return Type.from(new ActivationInfo(object));
|
|
}
|
|
return Type.from(object, domain);
|
|
});
|
|
new Verification(methodInfo, methodInfo.abc.applicationDomain, savedScope).verify();
|
|
methodInfo.verified = true;
|
|
Counter.count('Verifier: Methods');
|
|
} catch (e) {
|
|
if (e instanceof VerifierError) {
|
|
return;
|
|
}
|
|
throw e;
|
|
}
|
|
};
|
|
return verifier;
|
|
}();
|
|
(function (exports) {
|
|
var debug = false;
|
|
var IRDefinition = {
|
|
Control: {
|
|
Region: {
|
|
predecessors: {
|
|
array: true,
|
|
expand: 'control'
|
|
},
|
|
Start: {
|
|
_constructorText: 'this.control = this;',
|
|
scope: {
|
|
dynamic: true
|
|
},
|
|
domain: {
|
|
dynamic: true
|
|
}
|
|
}
|
|
},
|
|
End: {
|
|
control: {
|
|
assert: 'isControlOrNull'
|
|
},
|
|
Stop: {
|
|
store: {
|
|
assert: 'isStore'
|
|
},
|
|
argument: {
|
|
assert: ''
|
|
}
|
|
},
|
|
If: {
|
|
predicate: {
|
|
assert: ''
|
|
}
|
|
},
|
|
Switch: {
|
|
determinant: {
|
|
assert: ''
|
|
}
|
|
},
|
|
Jump: {}
|
|
}
|
|
},
|
|
Value: {
|
|
StoreDependent: {
|
|
control: {
|
|
assert: 'isControlOrNull',
|
|
nullable: true
|
|
},
|
|
store: {
|
|
assert: 'isStoreOrNull',
|
|
nullable: true
|
|
},
|
|
loads: {
|
|
dynamic: true,
|
|
nullable: true,
|
|
array: true
|
|
},
|
|
Call: {
|
|
callee: {
|
|
assert: ''
|
|
},
|
|
object: {
|
|
assert: 'isValueOrNull',
|
|
nullable: true
|
|
},
|
|
args: {
|
|
assert: 'isArray',
|
|
array: true
|
|
},
|
|
flags: {
|
|
internal: true,
|
|
assert: 'isNumber'
|
|
}
|
|
},
|
|
CallProperty: {
|
|
object: {
|
|
assert: ''
|
|
},
|
|
name: {
|
|
assert: ''
|
|
},
|
|
args: {
|
|
assert: 'isArray',
|
|
array: true
|
|
},
|
|
flags: {
|
|
internal: true,
|
|
assert: 'isNumber'
|
|
},
|
|
ASCallProperty: {
|
|
isLex: {
|
|
assert: '',
|
|
internal: true
|
|
}
|
|
},
|
|
ASCallSuper: {
|
|
scope: {
|
|
assert: ''
|
|
}
|
|
}
|
|
},
|
|
New: {
|
|
callee: {
|
|
assert: ''
|
|
},
|
|
args: {
|
|
assert: '',
|
|
array: true
|
|
},
|
|
ASNew: {}
|
|
},
|
|
GetProperty: {
|
|
object: {
|
|
assert: ''
|
|
},
|
|
name: {
|
|
assert: ''
|
|
},
|
|
ASGetProperty: {
|
|
flags: {
|
|
internal: true,
|
|
assert: 'isNumber'
|
|
}
|
|
},
|
|
ASGetDescendants: {},
|
|
ASHasProperty: {},
|
|
ASGetSlot: {},
|
|
ASGetSuper: {
|
|
scope: {
|
|
assert: ''
|
|
}
|
|
}
|
|
},
|
|
SetProperty: {
|
|
object: {
|
|
assert: ''
|
|
},
|
|
name: {
|
|
assert: ''
|
|
},
|
|
value: {
|
|
assert: ''
|
|
},
|
|
ASSetProperty: {
|
|
flags: {
|
|
internal: true
|
|
}
|
|
},
|
|
ASSetSlot: {},
|
|
ASSetSuper: {
|
|
scope: {
|
|
assert: ''
|
|
}
|
|
}
|
|
},
|
|
DeleteProperty: {
|
|
object: {
|
|
assert: ''
|
|
},
|
|
name: {
|
|
assert: ''
|
|
},
|
|
ASDeleteProperty: {}
|
|
},
|
|
ASFindProperty: {
|
|
scope: {
|
|
assert: ''
|
|
},
|
|
name: {
|
|
assert: ''
|
|
},
|
|
domain: {
|
|
assert: ''
|
|
},
|
|
strict: {
|
|
internal: true
|
|
}
|
|
}
|
|
},
|
|
Store: {},
|
|
Phi: {
|
|
control: {
|
|
assert: 'isControl',
|
|
nullable: true
|
|
},
|
|
args: {
|
|
array: true,
|
|
expand: 'value'
|
|
}
|
|
},
|
|
Variable: {
|
|
name: {
|
|
internal: true
|
|
}
|
|
},
|
|
Copy: {
|
|
argument: {}
|
|
},
|
|
Move: {
|
|
to: {},
|
|
from: {}
|
|
},
|
|
Projection: {
|
|
argument: {},
|
|
type: {
|
|
internal: true
|
|
},
|
|
selector: {
|
|
internal: true,
|
|
optional: true
|
|
}
|
|
},
|
|
Latch: {
|
|
control: {
|
|
assert: 'isControlOrNull',
|
|
nullable: true
|
|
},
|
|
condition: {},
|
|
left: {},
|
|
right: {}
|
|
},
|
|
Binary: {
|
|
operator: {
|
|
internal: true
|
|
},
|
|
left: {},
|
|
right: {}
|
|
},
|
|
Unary: {
|
|
operator: {
|
|
internal: true
|
|
},
|
|
argument: {}
|
|
},
|
|
Constant: {
|
|
value: {
|
|
internal: true
|
|
}
|
|
},
|
|
GlobalProperty: {
|
|
name: {
|
|
internal: true
|
|
}
|
|
},
|
|
This: {
|
|
control: {
|
|
assert: 'isControl'
|
|
}
|
|
},
|
|
Throw: {
|
|
control: {
|
|
assert: 'isControl'
|
|
},
|
|
argument: {}
|
|
},
|
|
Arguments: {
|
|
control: {
|
|
assert: 'isControl'
|
|
}
|
|
},
|
|
Parameter: {
|
|
control: {
|
|
assert: 'isControl'
|
|
},
|
|
index: {
|
|
internal: true
|
|
},
|
|
name: {
|
|
internal: true
|
|
}
|
|
},
|
|
NewArray: {
|
|
control: {
|
|
assert: 'isControl'
|
|
},
|
|
elements: {
|
|
array: true
|
|
}
|
|
},
|
|
NewObject: {
|
|
control: {
|
|
assert: 'isControl'
|
|
},
|
|
properties: {
|
|
array: true
|
|
}
|
|
},
|
|
KeyValuePair: {
|
|
key: {},
|
|
value: {}
|
|
},
|
|
ASScope: {
|
|
parent: {},
|
|
object: {},
|
|
isWith: {
|
|
internal: true
|
|
}
|
|
},
|
|
ASGlobal: {
|
|
control: {
|
|
assert: 'isControlOrNull',
|
|
nullable: true
|
|
},
|
|
scope: {
|
|
assert: 'isScope'
|
|
}
|
|
},
|
|
ASNewActivation: {
|
|
methodInfo: {
|
|
internal: true
|
|
}
|
|
},
|
|
ASMultiname: {
|
|
namespaces: {},
|
|
name: {},
|
|
flags: {
|
|
internal: true
|
|
}
|
|
}
|
|
}
|
|
};
|
|
function IRGenerator(root) {
|
|
var str = '';
|
|
function out(s) {
|
|
str += s + '\n';
|
|
}
|
|
var writer = new IndentingWriter(false, out);
|
|
function makeProperties(node) {
|
|
var result = [];
|
|
for (var k in node) {
|
|
if (isProperty(k)) {
|
|
node[k].name = k;
|
|
result.push(node[k]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function isProperty(v) {
|
|
if (v[0] === '_') {
|
|
return false;
|
|
}
|
|
return v[0].toLowerCase() === v[0];
|
|
}
|
|
function generate(node, path) {
|
|
path = path.concat([
|
|
node
|
|
]);
|
|
writer.enter('var ' + node._name + ' = (function () {');
|
|
var constructorName = node._name[0].toLowerCase() + node._name.slice(1) + 'Node';
|
|
if (constructorName.substring(0, 2) === 'aS') {
|
|
constructorName = 'as' + constructorName.substring(2);
|
|
}
|
|
var prototypeName = constructorName + '.prototype';
|
|
var properties = path.reduce(function (a, v) {
|
|
return a.concat(makeProperties(v));
|
|
}, []);
|
|
var parameters = properties.filter(function (property) {
|
|
return !property.dynamic;
|
|
});
|
|
var optionalParameters = parameters.filter(function (property) {
|
|
return property.optional;
|
|
});
|
|
var parameterString = parameters.map(function (property) {
|
|
if (property.expand) {
|
|
return property.expand;
|
|
}
|
|
return property.name;
|
|
}).join(', ');
|
|
writer.enter('function ' + constructorName + '(' + parameterString + ') {');
|
|
if (true) {
|
|
properties.forEach(function (property) {
|
|
if (property.assert === '') {
|
|
writer.writeLn('release || assert (!(' + property.name + ' == undefined), "' + property.name + '");');
|
|
} else if (property.assert) {
|
|
writer.writeLn('release || assert (' + property.assert + '(' + property.name + '), "' + property.name + '");');
|
|
}
|
|
});
|
|
writer.writeLn('release || assert (arguments.length >= ' + (parameters.length - optionalParameters.length) + ', "' + node._name + ' not enough args.");');
|
|
}
|
|
if (node._constructorText) {
|
|
writer.writeLn(node._constructorText);
|
|
}
|
|
properties.forEach(function (property) {
|
|
if (property.expand) {
|
|
writer.writeLn('this.' + property.name + ' = ' + property.expand + ' ? [' + property.expand + '] : [];');
|
|
} else if (property.dynamic) {
|
|
writer.writeLn('this.' + property.name + ' = undefined;');
|
|
} else {
|
|
writer.writeLn('this.' + property.name + ' = ' + property.name + ';');
|
|
}
|
|
});
|
|
writer.writeLn('this.id = nextID[nextID.length - 1] += 1;');
|
|
writer.leave('}');
|
|
if (path.length > 1) {
|
|
writer.writeLn(prototypeName + ' = ' + 'extend(' + path[path.length - 2]._name + ', "' + node._name + '");');
|
|
}
|
|
writer.writeLn(prototypeName + '.nodeName = "' + node._name + '";');
|
|
writer.enter(prototypeName + '.visitInputs = function (visitor) {');
|
|
properties.forEach(function (property) {
|
|
if (property.internal) {
|
|
return;
|
|
}
|
|
var str = '';
|
|
if (property.nullable) {
|
|
str += 'this.' + property.name + ' && ';
|
|
}
|
|
if (property.array) {
|
|
str += 'visitArrayInputs(this.' + property.name + ', visitor);';
|
|
} else {
|
|
str += 'visitor(this.' + property.name + ');';
|
|
}
|
|
writer.writeLn(str);
|
|
});
|
|
writer.leave('};');
|
|
writer.writeLn('return ' + constructorName + ';');
|
|
writer.leave('})();');
|
|
writer.writeLn('');
|
|
for (var name in node) {
|
|
if (name[0] === '_' || isProperty(name)) {
|
|
continue;
|
|
}
|
|
var child = node[name];
|
|
child._name = name;
|
|
generate(child, path);
|
|
}
|
|
}
|
|
IRDefinition._name = 'Node';
|
|
generate(IRDefinition, []);
|
|
return str;
|
|
}
|
|
var nextID = [];
|
|
var Node = function () {
|
|
function nodeNode() {
|
|
true;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
nodeNode.prototype.nodeName = 'Node';
|
|
nodeNode.prototype.visitInputs = function (visitor) {
|
|
};
|
|
return nodeNode;
|
|
}();
|
|
var Control = function () {
|
|
function controlNode() {
|
|
true;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
controlNode.prototype = extend(Node, 'Control');
|
|
controlNode.prototype.nodeName = 'Control';
|
|
controlNode.prototype.visitInputs = function (visitor) {
|
|
};
|
|
return controlNode;
|
|
}();
|
|
var Region = function () {
|
|
function regionNode(control) {
|
|
true;
|
|
this.predecessors = control ? [
|
|
control
|
|
] : [];
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
regionNode.prototype = extend(Control, 'Region');
|
|
regionNode.prototype.nodeName = 'Region';
|
|
regionNode.prototype.visitInputs = function (visitor) {
|
|
visitArrayInputs(this.predecessors, visitor);
|
|
};
|
|
return regionNode;
|
|
}();
|
|
var Start = function () {
|
|
function startNode(control) {
|
|
true;
|
|
this.control = this;
|
|
this.predecessors = control ? [
|
|
control
|
|
] : [];
|
|
this.scope = undefined;
|
|
this.domain = undefined;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
startNode.prototype = extend(Region, 'Start');
|
|
startNode.prototype.nodeName = 'Start';
|
|
startNode.prototype.visitInputs = function (visitor) {
|
|
visitArrayInputs(this.predecessors, visitor);
|
|
visitor(this.scope);
|
|
visitor(this.domain);
|
|
};
|
|
return startNode;
|
|
}();
|
|
var End = function () {
|
|
function endNode(control) {
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
endNode.prototype = extend(Control, 'End');
|
|
endNode.prototype.nodeName = 'End';
|
|
endNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
};
|
|
return endNode;
|
|
}();
|
|
var Stop = function () {
|
|
function stopNode(control, store, argument) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.argument = argument;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
stopNode.prototype = extend(End, 'Stop');
|
|
stopNode.prototype.nodeName = 'Stop';
|
|
stopNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
visitor(this.store);
|
|
visitor(this.argument);
|
|
};
|
|
return stopNode;
|
|
}();
|
|
var If = function () {
|
|
function ifNode(control, predicate) {
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.predicate = predicate;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
ifNode.prototype = extend(End, 'If');
|
|
ifNode.prototype.nodeName = 'If';
|
|
ifNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
visitor(this.predicate);
|
|
};
|
|
return ifNode;
|
|
}();
|
|
var Switch = function () {
|
|
function switchNode(control, determinant) {
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.determinant = determinant;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
switchNode.prototype = extend(End, 'Switch');
|
|
switchNode.prototype.nodeName = 'Switch';
|
|
switchNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
visitor(this.determinant);
|
|
};
|
|
return switchNode;
|
|
}();
|
|
var Jump = function () {
|
|
function jumpNode(control) {
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
jumpNode.prototype = extend(End, 'Jump');
|
|
jumpNode.prototype.nodeName = 'Jump';
|
|
jumpNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
};
|
|
return jumpNode;
|
|
}();
|
|
var Value = function () {
|
|
function valueNode() {
|
|
true;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
valueNode.prototype = extend(Node, 'Value');
|
|
valueNode.prototype.nodeName = 'Value';
|
|
valueNode.prototype.visitInputs = function (visitor) {
|
|
};
|
|
return valueNode;
|
|
}();
|
|
var StoreDependent = function () {
|
|
function storeDependentNode(control, store) {
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
storeDependentNode.prototype = extend(Value, 'StoreDependent');
|
|
storeDependentNode.prototype.nodeName = 'StoreDependent';
|
|
storeDependentNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
};
|
|
return storeDependentNode;
|
|
}();
|
|
var Call = function () {
|
|
function callNode(control, store, callee, object, args, flags) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.callee = callee;
|
|
this.object = object;
|
|
this.args = args;
|
|
this.flags = flags;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
callNode.prototype = extend(StoreDependent, 'Call');
|
|
callNode.prototype.nodeName = 'Call';
|
|
callNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.callee);
|
|
this.object && visitor(this.object);
|
|
visitArrayInputs(this.args, visitor);
|
|
};
|
|
return callNode;
|
|
}();
|
|
var CallProperty = function () {
|
|
function callPropertyNode(control, store, object, name, args, flags) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.args = args;
|
|
this.flags = flags;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
callPropertyNode.prototype = extend(StoreDependent, 'CallProperty');
|
|
callPropertyNode.prototype.nodeName = 'CallProperty';
|
|
callPropertyNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
visitArrayInputs(this.args, visitor);
|
|
};
|
|
return callPropertyNode;
|
|
}();
|
|
var ASCallProperty = function () {
|
|
function asCallPropertyNode(control, store, object, name, args, flags, isLex) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.args = args;
|
|
this.flags = flags;
|
|
this.isLex = isLex;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asCallPropertyNode.prototype = extend(CallProperty, 'ASCallProperty');
|
|
asCallPropertyNode.prototype.nodeName = 'ASCallProperty';
|
|
asCallPropertyNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
visitArrayInputs(this.args, visitor);
|
|
};
|
|
return asCallPropertyNode;
|
|
}();
|
|
var ASCallSuper = function () {
|
|
function asCallSuperNode(control, store, object, name, args, flags, scope) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.args = args;
|
|
this.flags = flags;
|
|
this.scope = scope;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asCallSuperNode.prototype = extend(CallProperty, 'ASCallSuper');
|
|
asCallSuperNode.prototype.nodeName = 'ASCallSuper';
|
|
asCallSuperNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
visitArrayInputs(this.args, visitor);
|
|
visitor(this.scope);
|
|
};
|
|
return asCallSuperNode;
|
|
}();
|
|
var New = function () {
|
|
function newNode(control, store, callee, args) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.callee = callee;
|
|
this.args = args;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
newNode.prototype = extend(StoreDependent, 'New');
|
|
newNode.prototype.nodeName = 'New';
|
|
newNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.callee);
|
|
visitArrayInputs(this.args, visitor);
|
|
};
|
|
return newNode;
|
|
}();
|
|
var ASNew = function () {
|
|
function asNewNode(control, store, callee, args) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.callee = callee;
|
|
this.args = args;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asNewNode.prototype = extend(New, 'ASNew');
|
|
asNewNode.prototype.nodeName = 'ASNew';
|
|
asNewNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.callee);
|
|
visitArrayInputs(this.args, visitor);
|
|
};
|
|
return asNewNode;
|
|
}();
|
|
var GetProperty = function () {
|
|
function getPropertyNode(control, store, object, name) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
getPropertyNode.prototype = extend(StoreDependent, 'GetProperty');
|
|
getPropertyNode.prototype.nodeName = 'GetProperty';
|
|
getPropertyNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
};
|
|
return getPropertyNode;
|
|
}();
|
|
var ASGetProperty = function () {
|
|
function asGetPropertyNode(control, store, object, name, flags) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.flags = flags;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asGetPropertyNode.prototype = extend(GetProperty, 'ASGetProperty');
|
|
asGetPropertyNode.prototype.nodeName = 'ASGetProperty';
|
|
asGetPropertyNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
};
|
|
return asGetPropertyNode;
|
|
}();
|
|
var ASGetDescendants = function () {
|
|
function asGetDescendantsNode(control, store, object, name) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asGetDescendantsNode.prototype = extend(GetProperty, 'ASGetDescendants');
|
|
asGetDescendantsNode.prototype.nodeName = 'ASGetDescendants';
|
|
asGetDescendantsNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
};
|
|
return asGetDescendantsNode;
|
|
}();
|
|
var ASHasProperty = function () {
|
|
function asHasPropertyNode(control, store, object, name) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asHasPropertyNode.prototype = extend(GetProperty, 'ASHasProperty');
|
|
asHasPropertyNode.prototype.nodeName = 'ASHasProperty';
|
|
asHasPropertyNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
};
|
|
return asHasPropertyNode;
|
|
}();
|
|
var ASGetSlot = function () {
|
|
function asGetSlotNode(control, store, object, name) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asGetSlotNode.prototype = extend(GetProperty, 'ASGetSlot');
|
|
asGetSlotNode.prototype.nodeName = 'ASGetSlot';
|
|
asGetSlotNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
};
|
|
return asGetSlotNode;
|
|
}();
|
|
var ASGetSuper = function () {
|
|
function asGetSuperNode(control, store, object, name, scope) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.scope = scope;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asGetSuperNode.prototype = extend(GetProperty, 'ASGetSuper');
|
|
asGetSuperNode.prototype.nodeName = 'ASGetSuper';
|
|
asGetSuperNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
visitor(this.scope);
|
|
};
|
|
return asGetSuperNode;
|
|
}();
|
|
var SetProperty = function () {
|
|
function setPropertyNode(control, store, object, name, value) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.value = value;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
setPropertyNode.prototype = extend(StoreDependent, 'SetProperty');
|
|
setPropertyNode.prototype.nodeName = 'SetProperty';
|
|
setPropertyNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
visitor(this.value);
|
|
};
|
|
return setPropertyNode;
|
|
}();
|
|
var ASSetProperty = function () {
|
|
function asSetPropertyNode(control, store, object, name, value, flags) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.value = value;
|
|
this.flags = flags;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asSetPropertyNode.prototype = extend(SetProperty, 'ASSetProperty');
|
|
asSetPropertyNode.prototype.nodeName = 'ASSetProperty';
|
|
asSetPropertyNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
visitor(this.value);
|
|
};
|
|
return asSetPropertyNode;
|
|
}();
|
|
var ASSetSlot = function () {
|
|
function asSetSlotNode(control, store, object, name, value) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.value = value;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asSetSlotNode.prototype = extend(SetProperty, 'ASSetSlot');
|
|
asSetSlotNode.prototype.nodeName = 'ASSetSlot';
|
|
asSetSlotNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
visitor(this.value);
|
|
};
|
|
return asSetSlotNode;
|
|
}();
|
|
var ASSetSuper = function () {
|
|
function asSetSuperNode(control, store, object, name, value, scope) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.value = value;
|
|
this.scope = scope;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asSetSuperNode.prototype = extend(SetProperty, 'ASSetSuper');
|
|
asSetSuperNode.prototype.nodeName = 'ASSetSuper';
|
|
asSetSuperNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
visitor(this.value);
|
|
visitor(this.scope);
|
|
};
|
|
return asSetSuperNode;
|
|
}();
|
|
var DeleteProperty = function () {
|
|
function deletePropertyNode(control, store, object, name) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
deletePropertyNode.prototype = extend(StoreDependent, 'DeleteProperty');
|
|
deletePropertyNode.prototype.nodeName = 'DeleteProperty';
|
|
deletePropertyNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
};
|
|
return deletePropertyNode;
|
|
}();
|
|
var ASDeleteProperty = function () {
|
|
function asDeletePropertyNode(control, store, object, name) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.object = object;
|
|
this.name = name;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asDeletePropertyNode.prototype = extend(DeleteProperty, 'ASDeleteProperty');
|
|
asDeletePropertyNode.prototype.nodeName = 'ASDeleteProperty';
|
|
asDeletePropertyNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.object);
|
|
visitor(this.name);
|
|
};
|
|
return asDeletePropertyNode;
|
|
}();
|
|
var ASFindProperty = function () {
|
|
function asFindPropertyNode(control, store, scope, name, domain, strict) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.store = store;
|
|
this.loads = undefined;
|
|
this.scope = scope;
|
|
this.name = name;
|
|
this.domain = domain;
|
|
this.strict = strict;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asFindPropertyNode.prototype = extend(StoreDependent, 'ASFindProperty');
|
|
asFindPropertyNode.prototype.nodeName = 'ASFindProperty';
|
|
asFindPropertyNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
this.store && visitor(this.store);
|
|
this.loads && visitArrayInputs(this.loads, visitor);
|
|
visitor(this.scope);
|
|
visitor(this.name);
|
|
visitor(this.domain);
|
|
};
|
|
return asFindPropertyNode;
|
|
}();
|
|
var Store = function () {
|
|
function storeNode() {
|
|
true;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
storeNode.prototype = extend(Value, 'Store');
|
|
storeNode.prototype.nodeName = 'Store';
|
|
storeNode.prototype.visitInputs = function (visitor) {
|
|
};
|
|
return storeNode;
|
|
}();
|
|
var Phi = function () {
|
|
function phiNode(control, value) {
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.args = value ? [
|
|
value
|
|
] : [];
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
phiNode.prototype = extend(Value, 'Phi');
|
|
phiNode.prototype.nodeName = 'Phi';
|
|
phiNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
visitArrayInputs(this.args, visitor);
|
|
};
|
|
return phiNode;
|
|
}();
|
|
var Variable = function () {
|
|
function variableNode(name) {
|
|
true;
|
|
this.name = name;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
variableNode.prototype = extend(Value, 'Variable');
|
|
variableNode.prototype.nodeName = 'Variable';
|
|
variableNode.prototype.visitInputs = function (visitor) {
|
|
};
|
|
return variableNode;
|
|
}();
|
|
var Copy = function () {
|
|
function copyNode(argument) {
|
|
true;
|
|
this.argument = argument;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
copyNode.prototype = extend(Value, 'Copy');
|
|
copyNode.prototype.nodeName = 'Copy';
|
|
copyNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.argument);
|
|
};
|
|
return copyNode;
|
|
}();
|
|
var Move = function () {
|
|
function moveNode(to, from) {
|
|
true;
|
|
this.to = to;
|
|
this.from = from;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
moveNode.prototype = extend(Value, 'Move');
|
|
moveNode.prototype.nodeName = 'Move';
|
|
moveNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.to);
|
|
visitor(this.from);
|
|
};
|
|
return moveNode;
|
|
}();
|
|
var Projection = function () {
|
|
function projectionNode(argument, type, selector) {
|
|
true;
|
|
this.argument = argument;
|
|
this.type = type;
|
|
this.selector = selector;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
projectionNode.prototype = extend(Value, 'Projection');
|
|
projectionNode.prototype.nodeName = 'Projection';
|
|
projectionNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.argument);
|
|
};
|
|
return projectionNode;
|
|
}();
|
|
var Latch = function () {
|
|
function latchNode(control, condition, left, right) {
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.condition = condition;
|
|
this.left = left;
|
|
this.right = right;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
latchNode.prototype = extend(Value, 'Latch');
|
|
latchNode.prototype.nodeName = 'Latch';
|
|
latchNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
visitor(this.condition);
|
|
visitor(this.left);
|
|
visitor(this.right);
|
|
};
|
|
return latchNode;
|
|
}();
|
|
var Binary = function () {
|
|
function binaryNode(operator, left, right) {
|
|
true;
|
|
this.operator = operator;
|
|
this.left = left;
|
|
this.right = right;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
binaryNode.prototype = extend(Value, 'Binary');
|
|
binaryNode.prototype.nodeName = 'Binary';
|
|
binaryNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.left);
|
|
visitor(this.right);
|
|
};
|
|
return binaryNode;
|
|
}();
|
|
var Unary = function () {
|
|
function unaryNode(operator, argument) {
|
|
true;
|
|
this.operator = operator;
|
|
this.argument = argument;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
unaryNode.prototype = extend(Value, 'Unary');
|
|
unaryNode.prototype.nodeName = 'Unary';
|
|
unaryNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.argument);
|
|
};
|
|
return unaryNode;
|
|
}();
|
|
var Constant = function () {
|
|
function constantNode(value) {
|
|
true;
|
|
this.value = value;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
constantNode.prototype = extend(Value, 'Constant');
|
|
constantNode.prototype.nodeName = 'Constant';
|
|
constantNode.prototype.visitInputs = function (visitor) {
|
|
};
|
|
return constantNode;
|
|
}();
|
|
var GlobalProperty = function () {
|
|
function globalPropertyNode(name) {
|
|
true;
|
|
this.name = name;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
globalPropertyNode.prototype = extend(Value, 'GlobalProperty');
|
|
globalPropertyNode.prototype.nodeName = 'GlobalProperty';
|
|
globalPropertyNode.prototype.visitInputs = function (visitor) {
|
|
};
|
|
return globalPropertyNode;
|
|
}();
|
|
var This = function () {
|
|
function thisNode(control) {
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
thisNode.prototype = extend(Value, 'This');
|
|
thisNode.prototype.nodeName = 'This';
|
|
thisNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
};
|
|
return thisNode;
|
|
}();
|
|
var Throw = function () {
|
|
function throwNode(control, argument) {
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.argument = argument;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
throwNode.prototype = extend(Value, 'Throw');
|
|
throwNode.prototype.nodeName = 'Throw';
|
|
throwNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
visitor(this.argument);
|
|
};
|
|
return throwNode;
|
|
}();
|
|
var Arguments = function () {
|
|
function argumentsNode(control) {
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
argumentsNode.prototype = extend(Value, 'Arguments');
|
|
argumentsNode.prototype.nodeName = 'Arguments';
|
|
argumentsNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
};
|
|
return argumentsNode;
|
|
}();
|
|
var Parameter = function () {
|
|
function parameterNode(control, index, name) {
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.index = index;
|
|
this.name = name;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
parameterNode.prototype = extend(Value, 'Parameter');
|
|
parameterNode.prototype.nodeName = 'Parameter';
|
|
parameterNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
};
|
|
return parameterNode;
|
|
}();
|
|
var NewArray = function () {
|
|
function newArrayNode(control, elements) {
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.elements = elements;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
newArrayNode.prototype = extend(Value, 'NewArray');
|
|
newArrayNode.prototype.nodeName = 'NewArray';
|
|
newArrayNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
visitArrayInputs(this.elements, visitor);
|
|
};
|
|
return newArrayNode;
|
|
}();
|
|
var NewObject = function () {
|
|
function newObjectNode(control, properties) {
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.properties = properties;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
newObjectNode.prototype = extend(Value, 'NewObject');
|
|
newObjectNode.prototype.nodeName = 'NewObject';
|
|
newObjectNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.control);
|
|
visitArrayInputs(this.properties, visitor);
|
|
};
|
|
return newObjectNode;
|
|
}();
|
|
var KeyValuePair = function () {
|
|
function keyValuePairNode(key, value) {
|
|
true;
|
|
this.key = key;
|
|
this.value = value;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
keyValuePairNode.prototype = extend(Value, 'KeyValuePair');
|
|
keyValuePairNode.prototype.nodeName = 'KeyValuePair';
|
|
keyValuePairNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.key);
|
|
visitor(this.value);
|
|
};
|
|
return keyValuePairNode;
|
|
}();
|
|
var ASScope = function () {
|
|
function asScopeNode(parent, object, isWith) {
|
|
true;
|
|
this.parent = parent;
|
|
this.object = object;
|
|
this.isWith = isWith;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asScopeNode.prototype = extend(Value, 'ASScope');
|
|
asScopeNode.prototype.nodeName = 'ASScope';
|
|
asScopeNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.parent);
|
|
visitor(this.object);
|
|
};
|
|
return asScopeNode;
|
|
}();
|
|
var ASGlobal = function () {
|
|
function asGlobalNode(control, scope) {
|
|
true;
|
|
true;
|
|
true;
|
|
this.control = control;
|
|
this.scope = scope;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asGlobalNode.prototype = extend(Value, 'ASGlobal');
|
|
asGlobalNode.prototype.nodeName = 'ASGlobal';
|
|
asGlobalNode.prototype.visitInputs = function (visitor) {
|
|
this.control && visitor(this.control);
|
|
visitor(this.scope);
|
|
};
|
|
return asGlobalNode;
|
|
}();
|
|
var ASNewActivation = function () {
|
|
function asNewActivationNode(methodInfo) {
|
|
true;
|
|
this.methodInfo = methodInfo;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asNewActivationNode.prototype = extend(Value, 'ASNewActivation');
|
|
asNewActivationNode.prototype.nodeName = 'ASNewActivation';
|
|
asNewActivationNode.prototype.visitInputs = function (visitor) {
|
|
};
|
|
return asNewActivationNode;
|
|
}();
|
|
var ASMultiname = function () {
|
|
function asMultinameNode(namespaces, name, flags) {
|
|
true;
|
|
this.namespaces = namespaces;
|
|
this.name = name;
|
|
this.flags = flags;
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
asMultinameNode.prototype = extend(Value, 'ASMultiname');
|
|
asMultinameNode.prototype.nodeName = 'ASMultiname';
|
|
asMultinameNode.prototype.visitInputs = function (visitor) {
|
|
visitor(this.namespaces);
|
|
visitor(this.name);
|
|
};
|
|
return asMultinameNode;
|
|
}();
|
|
function node() {
|
|
this.id = nextID[nextID.length - 1] += 1;
|
|
}
|
|
Node.startNumbering = function () {
|
|
nextID.push(0);
|
|
};
|
|
Node.stopNumbering = function () {
|
|
nextID.pop();
|
|
};
|
|
Node.prototype.toString = function (brief) {
|
|
if (brief) {
|
|
return nameOf(this);
|
|
}
|
|
var inputs = [];
|
|
this.visitInputs(function (input) {
|
|
inputs.push(nameOf(input));
|
|
});
|
|
var str = nameOf(this) + ' = ' + this.nodeName.toUpperCase();
|
|
if (this.toStringDetails) {
|
|
str += ' ' + this.toStringDetails();
|
|
}
|
|
if (inputs.length) {
|
|
str += ' ' + inputs.join(', ');
|
|
}
|
|
return str;
|
|
};
|
|
Node.prototype.visitInputsNoConstants = function visitInputs(visitor) {
|
|
this.visitInputs(function (node) {
|
|
if (isConstant(node)) {
|
|
return;
|
|
}
|
|
visitor(node);
|
|
});
|
|
};
|
|
Node.prototype.replaceInput = function (oldInput, newInput) {
|
|
var count = 0;
|
|
for (var k in this) {
|
|
var v = this[k];
|
|
if (v instanceof Node) {
|
|
if (v === oldInput) {
|
|
this[k] = newInput;
|
|
count++;
|
|
}
|
|
}
|
|
if (v instanceof Array) {
|
|
count += v.replace(oldInput, newInput);
|
|
}
|
|
}
|
|
return count;
|
|
};
|
|
Projection.Type = {
|
|
CASE: 'case',
|
|
TRUE: 'true',
|
|
FALSE: 'false',
|
|
STORE: 'store',
|
|
SCOPE: 'scope'
|
|
};
|
|
Projection.prototype.project = function () {
|
|
return this.argument;
|
|
};
|
|
Phi.prototype.seal = function seal() {
|
|
this.sealed = true;
|
|
};
|
|
Phi.prototype.pushValue = function pushValue(x) {
|
|
true;
|
|
true;
|
|
this.args.push(x);
|
|
};
|
|
KeyValuePair.prototype.mustFloat = true;
|
|
ASMultiname.prototype.mustFloat = true;
|
|
ASMultiname.prototype.isAttribute = function () {
|
|
return this.flags & 1;
|
|
};
|
|
var Flags = {
|
|
INDEXED: 1,
|
|
RESOLVED: 2,
|
|
PRISTINE: 4,
|
|
IS_METHOD: 8
|
|
};
|
|
var Operator = function () {
|
|
var map = {};
|
|
function operator(name, evaluate, binary) {
|
|
this.name = name;
|
|
this.binary = binary;
|
|
this.evaluate = evaluate;
|
|
map[name] = this;
|
|
}
|
|
operator.ADD = new operator('+', function (l, r) {
|
|
return l + r;
|
|
}, true);
|
|
operator.SUB = new operator('-', function (l, r) {
|
|
return l - r;
|
|
}, true);
|
|
operator.MUL = new operator('*', function (l, r) {
|
|
return l * r;
|
|
}, true);
|
|
operator.DIV = new operator('/', function (l, r) {
|
|
return l / r;
|
|
}, true);
|
|
operator.MOD = new operator('%', function (l, r) {
|
|
return l % r;
|
|
}, true);
|
|
operator.AND = new operator('&', function (l, r) {
|
|
return l & r;
|
|
}, true);
|
|
operator.OR = new operator('|', function (l, r) {
|
|
return l | r;
|
|
}, true);
|
|
operator.XOR = new operator('^', function (l, r) {
|
|
return l ^ r;
|
|
}, true);
|
|
operator.LSH = new operator('<<', function (l, r) {
|
|
return l << r;
|
|
}, true);
|
|
operator.RSH = new operator('>>', function (l, r) {
|
|
return l >> r;
|
|
}, true);
|
|
operator.URSH = new operator('>>>', function (l, r) {
|
|
return l >>> r;
|
|
}, true);
|
|
operator.SEQ = new operator('===', function (l, r) {
|
|
return l === r;
|
|
}, true);
|
|
operator.SNE = new operator('!==', function (l, r) {
|
|
return l !== r;
|
|
}, true);
|
|
operator.EQ = new operator('==', function (l, r) {
|
|
return l == r;
|
|
}, true);
|
|
operator.NE = new operator('!=', function (l, r) {
|
|
return l != r;
|
|
}, true);
|
|
operator.LE = new operator('<=', function (l, r) {
|
|
return l <= r;
|
|
}, true);
|
|
operator.GT = new operator('>', function (l, r) {
|
|
return l > r;
|
|
}, true);
|
|
operator.LT = new operator('<', function (l, r) {
|
|
return l < r;
|
|
}, true);
|
|
operator.GE = new operator('>=', function (l, r) {
|
|
return l >= r;
|
|
}, true);
|
|
operator.BITWISE_NOT = new operator('~', function (a) {
|
|
return ~a;
|
|
}, false);
|
|
operator.PLUS = new operator('+', function (a) {
|
|
return +a;
|
|
}, false);
|
|
operator.NEG = new operator('-', function (a) {
|
|
return -a;
|
|
}, false);
|
|
operator.TYPE_OF = new operator('typeof', function (a) {
|
|
return typeof a;
|
|
}, false);
|
|
operator.TRUE = new operator('!!', function (a) {
|
|
return !(!a);
|
|
}, false);
|
|
operator.FALSE = new operator('!', function (a) {
|
|
return !a;
|
|
}, false);
|
|
operator.AS_ADD = new operator('+', function (l, r) {
|
|
if (typeof l === 'string' || typeof r === 'string') {
|
|
return String(l) + String(r);
|
|
}
|
|
return l + r;
|
|
}, true);
|
|
function linkOpposites(a, b) {
|
|
a.not = b;
|
|
b.not = a;
|
|
}
|
|
linkOpposites(operator.SEQ, operator.SNE);
|
|
linkOpposites(operator.EQ, operator.NE);
|
|
linkOpposites(operator.TRUE, operator.FALSE);
|
|
operator.fromName = function fromName(name) {
|
|
return map[name];
|
|
};
|
|
operator.prototype.isBinary = function isBinary() {
|
|
return this.binary;
|
|
};
|
|
operator.prototype.toString = function toString() {
|
|
return this.name;
|
|
};
|
|
return operator;
|
|
}();
|
|
function extend(c, name) {
|
|
true;
|
|
return Object.create(c.prototype, {
|
|
nodeName: {
|
|
value: name
|
|
}
|
|
});
|
|
}
|
|
function nameOf(o) {
|
|
var useColors = false;
|
|
var result;
|
|
if (o instanceof Constant) {
|
|
if (o.value instanceof Multiname) {
|
|
return o.value.name;
|
|
}
|
|
return o.value;
|
|
} else if (o instanceof Variable) {
|
|
return o.name;
|
|
} else if (o instanceof Phi) {
|
|
return result = '|' + o.id + '|', useColors ? PURPLE + result + ENDC : result;
|
|
} else if (o instanceof Control) {
|
|
return result = '{' + o.id + '}', useColors ? RED + result + ENDC : result;
|
|
} else if (o instanceof Projection) {
|
|
if (o.type === Projection.Type.STORE) {
|
|
return result = '[' + o.id + '->' + o.argument.id + ']', useColors ? YELLOW + result + ENDC : result;
|
|
}
|
|
return result = '(' + o.id + ')', useColors ? GREEN + result + ENDC : result;
|
|
} else if (o instanceof Value) {
|
|
return result = '(' + o.id + ')', useColors ? GREEN + result + ENDC : result;
|
|
} else if (o instanceof Node) {
|
|
return o.id;
|
|
}
|
|
unexpected(o + ' ' + typeof o);
|
|
}
|
|
function toID(node) {
|
|
return node.id;
|
|
}
|
|
function visitArrayInputs(array, visitor) {
|
|
for (var i = 0; i < array.length; i++) {
|
|
visitor(array[i]);
|
|
}
|
|
}
|
|
function visitNothing() {
|
|
}
|
|
function isNotPhi(phi) {
|
|
return !isPhi(phi);
|
|
}
|
|
function isPhi(phi) {
|
|
return phi instanceof Phi;
|
|
}
|
|
function isScope(scope) {
|
|
return isPhi(scope) || scope instanceof ASScope || isProjection(scope, Projection.Type.SCOPE);
|
|
}
|
|
function isMultinameConstant(node) {
|
|
return node instanceof Constant && node.value instanceof Multiname;
|
|
}
|
|
function isMultiname(name) {
|
|
return isMultinameConstant(name) || name instanceof ASMultiname;
|
|
}
|
|
function isStore(store) {
|
|
return isPhi(store) || store instanceof Store || isProjection(store, Projection.Type.STORE);
|
|
}
|
|
function isConstant(constant) {
|
|
return constant instanceof Constant;
|
|
}
|
|
function isBoolean(boolean) {
|
|
return boolean === true || boolean === false;
|
|
}
|
|
function isInteger(integer) {
|
|
return integer | 0 === integer;
|
|
}
|
|
function isArray(array) {
|
|
return array instanceof Array;
|
|
}
|
|
function isControlOrNull(control) {
|
|
return isControl(control) || control === null;
|
|
}
|
|
function isStoreOrNull(store) {
|
|
return isStore(store) || store === null;
|
|
}
|
|
function isControl(control) {
|
|
return control instanceof Control;
|
|
}
|
|
function isValueOrNull(value) {
|
|
return isValue(value) || value === null;
|
|
}
|
|
function isValue(value) {
|
|
return value instanceof Value;
|
|
}
|
|
function isProjection(node, type) {
|
|
return node instanceof Projection && (!type || node.type === type);
|
|
}
|
|
var Null = new Constant(null);
|
|
var Undefined = new Constant(undefined);
|
|
Undefined.toString = function () {
|
|
return '_';
|
|
};
|
|
var Block = function () {
|
|
function block(id, start, end) {
|
|
if (start) {
|
|
true;
|
|
}
|
|
this.region = start;
|
|
this.id = id;
|
|
this.successors = [];
|
|
this.predecessors = [];
|
|
this.nodes = [
|
|
start,
|
|
end
|
|
];
|
|
}
|
|
block.prototype.pushSuccessorAt = function pushSuccessor(successor, index, pushPredecessor) {
|
|
true;
|
|
true;
|
|
this.successors[index] = successor;
|
|
if (pushPredecessor) {
|
|
successor.pushPredecessor(this);
|
|
}
|
|
};
|
|
block.prototype.pushSuccessor = function pushSuccessor(successor, pushPredecessor) {
|
|
true;
|
|
this.successors.push(successor);
|
|
if (pushPredecessor) {
|
|
successor.pushPredecessor(this);
|
|
}
|
|
};
|
|
block.prototype.pushPredecessor = function pushPredecessor(predecessor) {
|
|
true;
|
|
this.predecessors.push(predecessor);
|
|
};
|
|
block.prototype.visitNodes = function (fn) {
|
|
var nodes = this.nodes;
|
|
for (var i = 0, j = nodes.length; i < j; i++) {
|
|
fn(nodes[i]);
|
|
}
|
|
};
|
|
block.prototype.visitSuccessors = function (fn) {
|
|
var successors = this.successors;
|
|
for (var i = 0, j = successors.length; i < j; i++) {
|
|
fn(successors[i]);
|
|
}
|
|
};
|
|
block.prototype.visitPredecessors = function (fn) {
|
|
var predecessors = this.predecessors;
|
|
for (var i = 0, j = predecessors.length; i < j; i++) {
|
|
fn(predecessors[i]);
|
|
}
|
|
};
|
|
block.prototype.append = function (node) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
if (node.mustFloat) {
|
|
return;
|
|
}
|
|
this.nodes.splice(this.nodes.length - 1, 0, node);
|
|
};
|
|
block.prototype.toString = function () {
|
|
return 'B' + this.id + (this.name ? ' (' + this.name + ')' : '');
|
|
};
|
|
block.prototype.trace = function (writer) {
|
|
writer.writeLn(this);
|
|
};
|
|
return block;
|
|
}();
|
|
var DFG = function () {
|
|
function constructor(exit) {
|
|
this.exit = exit;
|
|
}
|
|
constructor.prototype.buildCFG = function () {
|
|
return CFG.fromDFG(this);
|
|
};
|
|
function preOrderDepthFirstSearch(root, visitChildren, pre) {
|
|
var visited = [];
|
|
var worklist = [
|
|
root
|
|
];
|
|
var push = worklist.push.bind(worklist);
|
|
var node;
|
|
while (node = worklist.pop()) {
|
|
if (visited[node.id] === 1) {
|
|
continue;
|
|
}
|
|
visited[node.id] = 1;
|
|
pre(node);
|
|
worklist.push(node);
|
|
visitChildren(node, push);
|
|
}
|
|
}
|
|
function postOrderDepthFirstSearch(root, visitChildren, post) {
|
|
var ONE_TIME = 1, MANY_TIMES = 2;
|
|
var visited = [];
|
|
var worklist = [
|
|
root
|
|
];
|
|
function visitChild(child) {
|
|
if (!visited[child.id]) {
|
|
worklist.push(child);
|
|
}
|
|
}
|
|
var node;
|
|
while (node = worklist.top()) {
|
|
if (visited[node.id]) {
|
|
if (visited[node.id] === ONE_TIME) {
|
|
visited[node.id] = MANY_TIMES;
|
|
post(node);
|
|
}
|
|
worklist.pop();
|
|
continue;
|
|
}
|
|
visited[node.id] = ONE_TIME;
|
|
visitChildren(node, visitChild);
|
|
}
|
|
}
|
|
constructor.prototype.forEachInPreOrderDepthFirstSearch = function forEachInPreOrderDepthFirstSearch(visitor) {
|
|
var visited = new Array(1024);
|
|
var worklist = [
|
|
this.exit
|
|
];
|
|
function push(node) {
|
|
if (isConstant(node)) {
|
|
return;
|
|
}
|
|
true;
|
|
worklist.push(node);
|
|
}
|
|
var node;
|
|
while (node = worklist.pop()) {
|
|
if (visited[node.id]) {
|
|
continue;
|
|
}
|
|
visited[node.id] = 1;
|
|
visitor && visitor(node);
|
|
worklist.push(node);
|
|
node.visitInputs(push);
|
|
}
|
|
};
|
|
constructor.prototype.forEach = function forEach(visitor, postOrder) {
|
|
var search = postOrder ? postOrderDepthFirstSearch : preOrderDepthFirstSearch;
|
|
search(this.exit, function (node, v) {
|
|
node.visitInputsNoConstants(v);
|
|
}, visitor);
|
|
};
|
|
constructor.prototype.traceMetrics = function (writer) {
|
|
var counter = new metrics.Counter(true);
|
|
preOrderDepthFirstSearch(this.exit, function (node, visitor) {
|
|
node.visitInputsNoConstants(visitor);
|
|
}, function (node) {
|
|
counter.count(node.nodeName);
|
|
});
|
|
counter.trace(writer);
|
|
};
|
|
constructor.prototype.trace = function (writer) {
|
|
var nodes = [];
|
|
var visited = {};
|
|
function colorOf(node) {
|
|
if (node instanceof Control) {
|
|
return 'yellow';
|
|
} else if (node instanceof Phi) {
|
|
return 'purple';
|
|
} else if (node instanceof Value) {
|
|
return 'green';
|
|
}
|
|
return 'white';
|
|
}
|
|
var blocks = [];
|
|
function followProjection(node) {
|
|
return node instanceof Projection ? node.project() : node;
|
|
}
|
|
function next(node) {
|
|
node = followProjection(node);
|
|
if (!visited[node.id]) {
|
|
visited[node.id] = true;
|
|
if (node.block) {
|
|
blocks.push(node.block);
|
|
}
|
|
nodes.push(node);
|
|
node.visitInputsNoConstants(next);
|
|
}
|
|
}
|
|
next(this.exit);
|
|
writer.writeLn('');
|
|
writer.enter('digraph DFG {');
|
|
writer.writeLn('graph [bgcolor = gray10];');
|
|
writer.writeLn('edge [color = white];');
|
|
writer.writeLn('node [shape = box, fontname = Consolas, fontsize = 11, color = white, fontcolor = white];');
|
|
writer.writeLn('rankdir = BT;');
|
|
function writeNode(node) {
|
|
writer.writeLn('N' + node.id + ' [label = "' + node.toString() + '", color = "' + colorOf(node) + '"];');
|
|
}
|
|
function defineNode(node) {
|
|
writer.writeLn('N' + node.id + ';');
|
|
}
|
|
blocks.forEach(function (block) {
|
|
writer.enter('subgraph cluster' + block.nodes[0].id + ' { bgcolor = gray20;');
|
|
block.visitNodes(function (node) {
|
|
defineNode(followProjection(node));
|
|
});
|
|
writer.leave('}');
|
|
});
|
|
nodes.forEach(writeNode);
|
|
nodes.forEach(function (node) {
|
|
node.visitInputsNoConstants(function (input) {
|
|
input = followProjection(input);
|
|
writer.writeLn('N' + node.id + ' -> ' + 'N' + input.id + ' [color=' + colorOf(input) + '];');
|
|
});
|
|
});
|
|
writer.leave('}');
|
|
writer.writeLn('');
|
|
};
|
|
return constructor;
|
|
}();
|
|
var CFG = function () {
|
|
function constructor() {
|
|
this.nextBlockID = 0;
|
|
this.blocks = [];
|
|
this.exit;
|
|
this.root;
|
|
}
|
|
constructor.fromDFG = function fromDFG(dfg) {
|
|
var cfg = new CFG();
|
|
true;
|
|
cfg.dfg = dfg;
|
|
var visited = [];
|
|
function buildEnd(end) {
|
|
if (end instanceof Projection) {
|
|
end = end.project();
|
|
}
|
|
true;
|
|
if (visited[end.id]) {
|
|
return;
|
|
}
|
|
visited[end.id] = true;
|
|
var start = end.control;
|
|
if (!(start instanceof Region)) {
|
|
start = end.control = new Region(start);
|
|
}
|
|
var block = start.block = cfg.buildBlock(start, end);
|
|
if (start instanceof Start) {
|
|
cfg.root = block;
|
|
}
|
|
for (var i = 0; i < start.predecessors.length; i++) {
|
|
var c = start.predecessors[i];
|
|
var d;
|
|
var trueProjection = false;
|
|
if (c instanceof Projection) {
|
|
d = c.project();
|
|
trueProjection = c.type === Projection.Type.TRUE;
|
|
} else {
|
|
d = c;
|
|
}
|
|
if (d instanceof Region) {
|
|
d = new Jump(c);
|
|
d = new Projection(d, Projection.Type.TRUE);
|
|
start.predecessors[i] = d;
|
|
d = d.project();
|
|
trueProjection = true;
|
|
}
|
|
buildEnd(d);
|
|
var controlBlock = d.control.block;
|
|
if (d instanceof Switch) {
|
|
true;
|
|
controlBlock.pushSuccessorAt(block, c.selector.value, true);
|
|
} else if (trueProjection && controlBlock.successors.length > 0) {
|
|
controlBlock.pushSuccessor(block, true);
|
|
controlBlock.hasFlippedSuccessors = true;
|
|
} else {
|
|
controlBlock.pushSuccessor(block, true);
|
|
}
|
|
}
|
|
}
|
|
buildEnd(dfg.exit);
|
|
cfg.splitCriticalEdges();
|
|
cfg.exit = dfg.exit.control.block;
|
|
cfg.computeDominators(true);
|
|
return cfg;
|
|
};
|
|
constructor.prototype.buildRootAndExit = function buildRootAndExit() {
|
|
true;
|
|
if (this.blocks[0].predecessors.length > 0) {
|
|
this.root = new Block(this.nextBlockID++);
|
|
this.blocks.push(this.root);
|
|
this.root.pushSuccessor(this.blocks[0], true);
|
|
} else {
|
|
this.root = this.blocks[0];
|
|
}
|
|
var exitBlocks = [];
|
|
for (var i = 0; i < this.blocks.length; i++) {
|
|
var block = this.blocks[i];
|
|
if (block.successors.length === 0) {
|
|
exitBlocks.push(block);
|
|
}
|
|
}
|
|
if (exitBlocks.length === 0) {
|
|
unexpected('Must have an exit block.');
|
|
} else if (exitBlocks.length === 1 && exitBlocks[0] !== this.root) {
|
|
this.exit = exitBlocks[0];
|
|
} else {
|
|
this.exit = new Block(this.nextBlockID++);
|
|
this.blocks.push(this.exit);
|
|
for (var i = 0; i < exitBlocks.length; i++) {
|
|
exitBlocks[i].pushSuccessor(this.exit, true);
|
|
}
|
|
}
|
|
true;
|
|
true;
|
|
};
|
|
constructor.prototype.fromString = function (list, rootName) {
|
|
var cfg = this;
|
|
var names = cfg.blockNames || (cfg.blockNames = {});
|
|
var blocks = cfg.blocks;
|
|
var sets = list.replace(/\ /g, '').split(',');
|
|
sets.forEach(function (set) {
|
|
var edgeList = set.split('->');
|
|
var last = null;
|
|
for (var i = 0; i < edgeList.length; i++) {
|
|
var next = edgeList[i];
|
|
if (last) {
|
|
buildEdge(last, next);
|
|
} else {
|
|
buildBlock(next);
|
|
}
|
|
last = next;
|
|
}
|
|
});
|
|
function buildBlock(name) {
|
|
var block = names[name];
|
|
if (block) {
|
|
return block;
|
|
}
|
|
names[name] = block = new Block(cfg.nextBlockID++);
|
|
block.name = name;
|
|
blocks.push(block);
|
|
return block;
|
|
}
|
|
function buildEdge(from, to) {
|
|
buildBlock(from).pushSuccessor(buildBlock(to), true);
|
|
}
|
|
true;
|
|
this.root = names[rootName];
|
|
};
|
|
constructor.prototype.buildBlock = function (start, end) {
|
|
var block = new Block(this.nextBlockID++, start, end);
|
|
this.blocks.push(block);
|
|
return block;
|
|
};
|
|
constructor.prototype.createBlockSet = function () {
|
|
if (!this.setConstructor) {
|
|
this.setConstructor = BitSetFunctor(this.blocks.length);
|
|
}
|
|
return new this.setConstructor();
|
|
};
|
|
constructor.prototype.computeReversePostOrder = function computeReversePostOrder() {
|
|
if (this.order) {
|
|
return this.order;
|
|
}
|
|
var order = this.order = [];
|
|
this.depthFirstSearch(null, order.push.bind(order));
|
|
order.reverse();
|
|
for (var i = 0; i < order.length; i++) {
|
|
order[i].rpo = i;
|
|
}
|
|
return order;
|
|
};
|
|
constructor.prototype.depthFirstSearch = function depthFirstSearch(preFn, postFn) {
|
|
var visited = this.createBlockSet();
|
|
function visit(node) {
|
|
visited.set(node.id);
|
|
if (preFn)
|
|
preFn(node);
|
|
var successors = node.successors;
|
|
for (var i = 0, j = successors.length; i < j; i++) {
|
|
var s = successors[i];
|
|
if (!visited.get(s.id)) {
|
|
visit(s);
|
|
}
|
|
}
|
|
if (postFn)
|
|
postFn(node);
|
|
}
|
|
visit(this.root);
|
|
};
|
|
constructor.prototype.computeDominators = function (apply) {
|
|
true;
|
|
var dom = new Int32Array(this.blocks.length);
|
|
for (var i = 0; i < dom.length; i++) {
|
|
dom[i] = -1;
|
|
}
|
|
var map = this.createBlockSet();
|
|
function computeCommonDominator(a, b) {
|
|
map.clearAll();
|
|
while (a >= 0) {
|
|
map.set(a);
|
|
a = dom[a];
|
|
}
|
|
while (b >= 0 && !map.get(b)) {
|
|
b = dom[b];
|
|
}
|
|
return b;
|
|
}
|
|
function computeDominator(blockID, parentID) {
|
|
if (dom[blockID] < 0) {
|
|
dom[blockID] = parentID;
|
|
} else {
|
|
dom[blockID] = computeCommonDominator(dom[blockID], parentID);
|
|
}
|
|
}
|
|
this.depthFirstSearch(function visit(block) {
|
|
var s = block.successors;
|
|
for (var i = 0, j = s.length; i < j; i++) {
|
|
computeDominator(s[i].id, block.id);
|
|
}
|
|
});
|
|
if (apply) {
|
|
for (var i = 0, j = this.blocks.length; i < j; i++) {
|
|
this.blocks[i].dominator = this.blocks[dom[i]];
|
|
}
|
|
function computeDominatorDepth(block) {
|
|
var dominatorDepth;
|
|
if (block.dominatorDepth !== undefined) {
|
|
return block.dominatorDepth;
|
|
} else if (!block.dominator) {
|
|
dominatorDepth = 0;
|
|
} else {
|
|
dominatorDepth = computeDominatorDepth(block.dominator) + 1;
|
|
}
|
|
return block.dominatorDepth = dominatorDepth;
|
|
}
|
|
for (var i = 0, j = this.blocks.length; i < j; i++) {
|
|
computeDominatorDepth(this.blocks[i]);
|
|
}
|
|
}
|
|
return dom;
|
|
};
|
|
constructor.prototype.computeLoops = function computeLoops() {
|
|
var active = this.createBlockSet();
|
|
var visited = this.createBlockSet();
|
|
var nextLoop = 0;
|
|
function makeLoopHeader(block) {
|
|
if (!block.isLoopHeader) {
|
|
block.isLoopHeader = true;
|
|
block.loops = 1 << nextLoop;
|
|
nextLoop += 1;
|
|
}
|
|
}
|
|
function visit(block) {
|
|
if (visited.get(block.id)) {
|
|
if (active.get(block.id)) {
|
|
makeLoopHeader(block);
|
|
}
|
|
return block.loops;
|
|
}
|
|
visited.set(block.id);
|
|
active.set(block.id);
|
|
var loops = 0;
|
|
for (var i = 0, j = block.successors.length; i < j; i++) {
|
|
loops |= visit(block.successors[i]);
|
|
}
|
|
if (block.isLoopHeader) {
|
|
loops &= ~block.loops;
|
|
}
|
|
block.loops = loops;
|
|
active.clear(block.id);
|
|
return loops;
|
|
}
|
|
var loop = visit(this.root);
|
|
};
|
|
function followProjection(node) {
|
|
return node instanceof Projection ? node.project() : node;
|
|
}
|
|
var Uses = function () {
|
|
function constructor() {
|
|
this.entries = [];
|
|
}
|
|
constructor.prototype.addUse = function addUse(def, use) {
|
|
var entry = this.entries[def.id];
|
|
if (!entry) {
|
|
entry = this.entries[def.id] = {
|
|
def: def,
|
|
uses: []
|
|
};
|
|
}
|
|
entry.uses.pushUnique(use);
|
|
};
|
|
constructor.prototype.trace = function (writer) {
|
|
writer.enter('> Uses');
|
|
this.entries.forEach(function (entry) {
|
|
writer.writeLn(entry.def.id + ' -> [' + entry.uses.map(toID).join(', ') + '] ' + entry.def);
|
|
});
|
|
writer.leave('<');
|
|
};
|
|
constructor.prototype.replace = function (def, value) {
|
|
var entry = this.entries[def.id];
|
|
if (entry.uses.length === 0) {
|
|
return false;
|
|
}
|
|
var count = 0;
|
|
entry.uses.forEach(function (use) {
|
|
count += use.replaceInput(def, value);
|
|
});
|
|
true;
|
|
entry.uses = [];
|
|
return true;
|
|
};
|
|
function updateUses(def, value) {
|
|
debug && writer.writeLn('Update ' + def + ' with ' + value);
|
|
var entry = useEntries[def.id];
|
|
if (entry.uses.length === 0) {
|
|
return false;
|
|
}
|
|
debug && writer.writeLn('Replacing: ' + def.id + ' in [' + entry.uses.map(toID).join(', ') + '] with ' + value.id);
|
|
var count = 0;
|
|
entry.uses.forEach(function (use) {
|
|
count += use.replaceInput(def, value);
|
|
});
|
|
true;
|
|
entry.uses = [];
|
|
return true;
|
|
}
|
|
return constructor;
|
|
}();
|
|
constructor.prototype.computeUses = function computeUses() {
|
|
Timer.start('computeUses');
|
|
var writer = debug && new IndentingWriter();
|
|
debug && writer.enter('> Compute Uses');
|
|
var dfg = this.dfg;
|
|
var uses = new Uses();
|
|
dfg.forEachInPreOrderDepthFirstSearch(function (use) {
|
|
use.visitInputs(function (def) {
|
|
uses.addUse(def, use);
|
|
});
|
|
});
|
|
if (debug) {
|
|
writer.enter('> Uses');
|
|
uses.entries.forEach(function (entry) {
|
|
writer.writeLn(entry.def.id + ' -> [' + entry.uses.map(toID).join(', ') + '] ' + entry.def);
|
|
});
|
|
writer.leave('<');
|
|
writer.leave('<');
|
|
}
|
|
Timer.stop();
|
|
return uses;
|
|
};
|
|
constructor.prototype.verify = function verify() {
|
|
var writer = debug && new IndentingWriter();
|
|
debug && writer.enter('> Verify');
|
|
var order = this.computeReversePostOrder();
|
|
order.forEach(function (block) {
|
|
if (block.phis) {
|
|
block.phis.forEach(function (phi) {
|
|
true;
|
|
true;
|
|
});
|
|
}
|
|
});
|
|
debug && writer.leave('<');
|
|
};
|
|
constructor.prototype.optimizePhis = function optimizePhis() {
|
|
var writer = debug && new IndentingWriter();
|
|
debug && writer.enter('> Optimize Phis');
|
|
var phis = [];
|
|
var useEntries = this.computeUses().entries;
|
|
useEntries.forEach(function (entry) {
|
|
if (isPhi(entry.def)) {
|
|
phis.push(entry.def);
|
|
}
|
|
});
|
|
debug && writer.writeLn('Trying to optimize ' + phis.length + ' phis.');
|
|
function updateUses(def, value) {
|
|
debug && writer.writeLn('Update ' + def + ' with ' + value);
|
|
var entry = useEntries[def.id];
|
|
if (entry.uses.length === 0) {
|
|
return false;
|
|
}
|
|
debug && writer.writeLn('Replacing: ' + def.id + ' in [' + entry.uses.map(toID).join(', ') + '] with ' + value.id);
|
|
var count = 0;
|
|
var entryUses = entry.uses;
|
|
for (var i = 0, j = entryUses.length; i < j; i++) {
|
|
count += entryUses[i].replaceInput(def, value);
|
|
}
|
|
true;
|
|
entry.uses = [];
|
|
return true;
|
|
}
|
|
function simplify(phi, args) {
|
|
args = args.unique();
|
|
if (args.length === 1) {
|
|
return args[0];
|
|
} else {
|
|
if (args.length === 2) {
|
|
if (args[0] === phi) {
|
|
return args[1];
|
|
} else if (args[1] === phi) {
|
|
return args[0];
|
|
}
|
|
return phi;
|
|
}
|
|
}
|
|
return phi;
|
|
}
|
|
var count = 0;
|
|
var iterations = 0;
|
|
var changed = true;
|
|
while (changed) {
|
|
iterations++;
|
|
changed = false;
|
|
phis.forEach(function (phi) {
|
|
var value = simplify(phi, phi.args);
|
|
if (value !== phi) {
|
|
if (updateUses(phi, value)) {
|
|
changed = true;
|
|
count++;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if (debug) {
|
|
writer.writeLn('Simplified ' + count + ' phis, in ' + iterations + ' iterations.');
|
|
writer.leave('<');
|
|
}
|
|
};
|
|
constructor.prototype.splitCriticalEdges = function splitCriticalEdges() {
|
|
var writer = debug && new IndentingWriter();
|
|
var blocks = this.blocks;
|
|
var criticalEdges = [];
|
|
debug && writer.enter('> Splitting Critical Edges');
|
|
for (var i = 0; i < blocks.length; i++) {
|
|
var successors = blocks[i].successors;
|
|
if (successors.length > 1) {
|
|
for (var j = 0; j < successors.length; j++) {
|
|
if (successors[j].predecessors.length > 1) {
|
|
criticalEdges.push({
|
|
from: blocks[i],
|
|
to: successors[j]
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var criticalEdgeCount = criticalEdges.length;
|
|
if (criticalEdgeCount && debug) {
|
|
writer.writeLn('Splitting: ' + criticalEdgeCount);
|
|
this.trace(writer);
|
|
}
|
|
var edge;
|
|
while (edge = criticalEdges.pop()) {
|
|
var fromIndex = edge.from.successors.indexOf(edge.to);
|
|
var toIndex = edge.to.predecessors.indexOf(edge.from);
|
|
true;
|
|
debug && writer.writeLn('Splitting critical edge: ' + edge.from + ' -> ' + edge.to);
|
|
var toBlock = edge.to;
|
|
var toRegion = toBlock.region;
|
|
var control = toRegion.predecessors[toIndex];
|
|
var region = new Region(control);
|
|
var jump = new Jump(region);
|
|
var block = this.buildBlock(region, jump);
|
|
toRegion.predecessors[toIndex] = new Projection(jump, Projection.Type.TRUE);
|
|
var fromBlock = edge.from;
|
|
fromBlock.successors[fromIndex] = block;
|
|
block.pushPredecessor(fromBlock);
|
|
block.pushSuccessor(toBlock);
|
|
toBlock.predecessors[toIndex] = block;
|
|
}
|
|
if (criticalEdgeCount && debug) {
|
|
this.trace(writer);
|
|
}
|
|
if (criticalEdgeCount && !true) {
|
|
true;
|
|
}
|
|
debug && writer.leave('<');
|
|
return criticalEdgeCount;
|
|
};
|
|
constructor.prototype.allocateVariables = function allocateVariables() {
|
|
var writer = debug && new IndentingWriter();
|
|
debug && writer.enter('> Allocating Virtual Registers');
|
|
var order = this.computeReversePostOrder();
|
|
function allocate(node) {
|
|
if (isProjection(node, Projection.Type.STORE)) {
|
|
return;
|
|
}
|
|
if (node instanceof SetProperty) {
|
|
return;
|
|
}
|
|
if (node instanceof Value) {
|
|
node.variable = new Variable('v' + node.id);
|
|
debug && writer.writeLn('Allocated: ' + node.variable + ' to ' + node);
|
|
}
|
|
}
|
|
order.forEach(function (block) {
|
|
block.nodes.forEach(allocate);
|
|
if (block.phis) {
|
|
block.phis.forEach(allocate);
|
|
}
|
|
});
|
|
var blockMoves = [];
|
|
for (var i = 0; i < order.length; i++) {
|
|
var block = order[i];
|
|
var phis = block.phis;
|
|
var predecessors = block.predecessors;
|
|
if (phis) {
|
|
for (var j = 0; j < phis.length; j++) {
|
|
var phi = phis[j];
|
|
debug && writer.writeLn('Emitting moves for: ' + phi);
|
|
var arguments = phi.args;
|
|
true;
|
|
for (var k = 0; k < predecessors.length; k++) {
|
|
var predecessor = predecessors[k];
|
|
var argument = arguments[k];
|
|
if (argument.abstract || isProjection(argument, Projection.Type.STORE)) {
|
|
continue;
|
|
}
|
|
var moves = blockMoves[predecessor.id] || (blockMoves[predecessor.id] = []);
|
|
argument = argument.variable || argument;
|
|
if (phi.variable !== argument) {
|
|
moves.push(new Move(phi.variable, argument));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var blocks = this.blocks;
|
|
blockMoves.forEach(function (moves, blockID) {
|
|
var block = blocks[blockID];
|
|
var temporary = 0;
|
|
debug && writer.writeLn(block + ' Moves: ' + moves);
|
|
while (moves.length) {
|
|
for (var i = 0; i < moves.length; i++) {
|
|
var move = moves[i];
|
|
for (var j = 0; j < moves.length; j++) {
|
|
if (i === j) {
|
|
continue;
|
|
}
|
|
if (moves[j].from === move.to) {
|
|
move = null;
|
|
break;
|
|
}
|
|
}
|
|
if (move) {
|
|
moves.splice(i--, 1);
|
|
block.append(move);
|
|
}
|
|
}
|
|
if (moves.length) {
|
|
debug && writer.writeLn('Breaking Cycle');
|
|
var move = moves[0];
|
|
var temp = new Variable('t' + temporary++);
|
|
blocks[blockID].append(new Move(temp, move.to));
|
|
for (var i = 1; i < moves.length; i++) {
|
|
if (moves[i].from === move.to) {
|
|
moves[i].from = temp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
debug && writer.leave('<');
|
|
};
|
|
constructor.prototype.scheduleEarly = function scheduleEarly() {
|
|
var debugScheduler = false;
|
|
var writer = debugScheduler && new IndentingWriter();
|
|
debugScheduler && writer.enter('> Schedule Early');
|
|
var cfg = this;
|
|
var dfg = this.dfg;
|
|
var scheduled = [];
|
|
var roots = [];
|
|
dfg.forEachInPreOrderDepthFirstSearch(function (node) {
|
|
if (node instanceof Region || node instanceof Jump) {
|
|
return;
|
|
}
|
|
if (node.control) {
|
|
roots.push(node);
|
|
}
|
|
if (isPhi(node)) {
|
|
node.args.forEach(function (input) {
|
|
if (shouldFloat(input)) {
|
|
input.mustNotFloat = true;
|
|
}
|
|
});
|
|
}
|
|
}, true);
|
|
if (debugScheduler) {
|
|
roots.forEach(function (node) {
|
|
print('Root: ' + node);
|
|
});
|
|
}
|
|
for (var i = 0; i < roots.length; i++) {
|
|
var root = roots[i];
|
|
if (root instanceof Phi) {
|
|
var block = root.control.block;
|
|
(block.phis || (block.phis = [])).push(root);
|
|
}
|
|
if (root.control) {
|
|
schedule(root);
|
|
}
|
|
}
|
|
function isScheduled(node) {
|
|
return scheduled[node.id];
|
|
}
|
|
function shouldFloat(node) {
|
|
if (node.mustNotFloat || node.shouldNotFloat) {
|
|
return false;
|
|
}
|
|
if (node.mustFloat || node.shouldFloat) {
|
|
return true;
|
|
}
|
|
if (node instanceof Parameter || node instanceof This || node instanceof Arguments) {
|
|
return true;
|
|
}
|
|
return node instanceof Binary || node instanceof Unary || node instanceof Parameter;
|
|
}
|
|
function append(node) {
|
|
true;
|
|
scheduled[node.id] = true;
|
|
true;
|
|
if (shouldFloat(node)) {
|
|
} else {
|
|
node.control.block.append(node);
|
|
}
|
|
}
|
|
function scheduleIn(node, region) {
|
|
true;
|
|
true;
|
|
true;
|
|
debugScheduler && writer.writeLn('Scheduled: ' + node + ' in ' + region);
|
|
node.control = region;
|
|
append(node);
|
|
}
|
|
function schedule(node) {
|
|
debugScheduler && writer.enter('> Schedule: ' + node);
|
|
var inputs = [];
|
|
node.visitInputs(function (input) {
|
|
if (isConstant(input)) {
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
if (isValue(input)) {
|
|
inputs.push(followProjection(input));
|
|
}
|
|
});
|
|
debugScheduler && writer.writeLn('Inputs: [' + inputs.map(toID) + '], length: ' + inputs.length);
|
|
for (var i = 0; i < inputs.length; i++) {
|
|
var input = inputs[i];
|
|
if (isNotPhi(input) && !isScheduled(input)) {
|
|
schedule(input);
|
|
}
|
|
}
|
|
if (node.control) {
|
|
if (node instanceof End || node instanceof Phi || node instanceof Start || isScheduled(node)) {
|
|
} else {
|
|
append(node);
|
|
}
|
|
} else {
|
|
if (inputs.length) {
|
|
var x = inputs[0].control;
|
|
for (var i = 1; i < inputs.length; i++) {
|
|
var y = inputs[i].control;
|
|
if (x.block.dominatorDepth < y.block.dominatorDepth) {
|
|
x = y;
|
|
}
|
|
}
|
|
scheduleIn(node, x);
|
|
} else {
|
|
scheduleIn(node, cfg.root.region);
|
|
}
|
|
}
|
|
debugScheduler && writer.leave('<');
|
|
}
|
|
debugScheduler && writer.leave('<');
|
|
roots.forEach(function (node) {
|
|
node = followProjection(node);
|
|
if (node === dfg.start || node instanceof Region) {
|
|
return;
|
|
}
|
|
true;
|
|
});
|
|
};
|
|
constructor.prototype.trace = function (writer) {
|
|
var visited = [];
|
|
var blocks = [];
|
|
function next(block) {
|
|
if (!visited[block.id]) {
|
|
visited[block.id] = true;
|
|
blocks.push(block);
|
|
block.visitSuccessors(next);
|
|
}
|
|
}
|
|
var root = this.root;
|
|
var exit = this.exit;
|
|
next(root);
|
|
function colorOf(block) {
|
|
return 'black';
|
|
}
|
|
function styleOf(block) {
|
|
return 'filled';
|
|
}
|
|
function shapeOf(block) {
|
|
true;
|
|
if (block === root) {
|
|
return 'house';
|
|
} else if (block === exit) {
|
|
return 'invhouse';
|
|
}
|
|
return 'box';
|
|
}
|
|
writer.writeLn('');
|
|
writer.enter('digraph CFG {');
|
|
writer.writeLn('graph [bgcolor = gray10];');
|
|
writer.writeLn('edge [fontname = Consolas, fontsize = 11, color = white, fontcolor = white];');
|
|
writer.writeLn('node [shape = box, fontname = Consolas, fontsize = 11, color = white, fontcolor = white, style = filled];');
|
|
writer.writeLn('rankdir = TB;');
|
|
blocks.forEach(function (block) {
|
|
var loopInfo = '';
|
|
var blockInfo = '';
|
|
var intervalInfo = '';
|
|
if (block.loops !== undefined) {
|
|
}
|
|
if (block.name !== undefined) {
|
|
blockInfo += ' ' + block.name;
|
|
}
|
|
if (block.rpo !== undefined) {
|
|
blockInfo += ' O: ' + block.rpo;
|
|
}
|
|
writer.writeLn('B' + block.id + ' [label = "B' + block.id + blockInfo + loopInfo + '", fillcolor = "' + colorOf(block) + '", shape=' + shapeOf(block) + ', style=' + styleOf(block) + '];');
|
|
});
|
|
blocks.forEach(function (block) {
|
|
block.visitSuccessors(function (successor) {
|
|
writer.writeLn('B' + block.id + ' -> ' + 'B' + successor.id);
|
|
});
|
|
if (block.dominator) {
|
|
writer.writeLn('B' + block.id + ' -> ' + 'B' + block.dominator.id + ' [color = orange];');
|
|
}
|
|
if (block.follow) {
|
|
writer.writeLn('B' + block.id + ' -> ' + 'B' + block.follow.id + ' [color = purple];');
|
|
}
|
|
});
|
|
writer.leave('}');
|
|
writer.writeLn('');
|
|
};
|
|
return constructor;
|
|
}();
|
|
var PeepholeOptimizer = function () {
|
|
function constructor() {
|
|
}
|
|
function foldUnary(node, truthy) {
|
|
true;
|
|
if (isConstant(node.argument)) {
|
|
return new Constant(node.operator.evaluate(node.argument.value));
|
|
}
|
|
if (truthy) {
|
|
var argument = fold(node.argument, true);
|
|
if (node.operator === Operator.TRUE) {
|
|
return argument;
|
|
}
|
|
if (argument instanceof Unary) {
|
|
if (node.operator === Operator.FALSE && argument.operator === Operator.FALSE) {
|
|
return argument.argument;
|
|
}
|
|
} else {
|
|
return new Unary(node.operator, argument);
|
|
}
|
|
}
|
|
return node;
|
|
}
|
|
function foldBinary(node, truthy) {
|
|
true;
|
|
if (isConstant(node.left) && isConstant(node.right)) {
|
|
return new Constant(node.operator.evaluate(node.left.value, node.right.value));
|
|
}
|
|
return node;
|
|
}
|
|
function fold(node, truthy) {
|
|
if (node instanceof Unary) {
|
|
return foldUnary(node, truthy);
|
|
} else if (node instanceof Binary) {
|
|
return foldBinary(node, truthy);
|
|
}
|
|
return node;
|
|
}
|
|
constructor.prototype.tryFold = fold;
|
|
return constructor;
|
|
}();
|
|
exports.isConstant = isConstant;
|
|
exports.Block = Block;
|
|
exports.Node = Node;
|
|
exports.Start = Start;
|
|
exports.Null = Null;
|
|
exports.Undefined = Undefined;
|
|
exports.This = This;
|
|
exports.Throw = Throw;
|
|
exports.Arguments = Arguments;
|
|
exports.ASGlobal = ASGlobal;
|
|
exports.Projection = Projection;
|
|
exports.Region = Region;
|
|
exports.Latch = Latch;
|
|
exports.Binary = Binary;
|
|
exports.Unary = Unary;
|
|
exports.Constant = Constant;
|
|
exports.ASFindProperty = ASFindProperty;
|
|
exports.GlobalProperty = GlobalProperty;
|
|
exports.GetProperty = GetProperty;
|
|
exports.SetProperty = SetProperty;
|
|
exports.CallProperty = CallProperty;
|
|
exports.ASCallProperty = ASCallProperty;
|
|
exports.ASCallSuper = ASCallSuper;
|
|
exports.ASGetProperty = ASGetProperty;
|
|
exports.ASGetSuper = ASGetSuper;
|
|
exports.ASHasProperty = ASHasProperty;
|
|
exports.ASDeleteProperty = ASDeleteProperty;
|
|
exports.ASGetDescendants = ASGetDescendants;
|
|
exports.ASSetProperty = ASSetProperty;
|
|
exports.ASSetSuper = ASSetSuper;
|
|
exports.ASGetSlot = ASGetSlot;
|
|
exports.ASSetSlot = ASSetSlot;
|
|
exports.Call = Call;
|
|
exports.ASNew = ASNew;
|
|
exports.Phi = Phi;
|
|
exports.Stop = Stop;
|
|
exports.If = If;
|
|
exports.Switch = Switch;
|
|
exports.End = End;
|
|
exports.Jump = Jump;
|
|
exports.ASScope = ASScope;
|
|
exports.Operator = Operator;
|
|
exports.Variable = Variable;
|
|
exports.Move = Move;
|
|
exports.Copy = Copy;
|
|
exports.Parameter = Parameter;
|
|
exports.NewArray = NewArray;
|
|
exports.NewObject = NewObject;
|
|
exports.ASNewActivation = ASNewActivation;
|
|
exports.KeyValuePair = KeyValuePair;
|
|
exports.ASMultiname = ASMultiname;
|
|
exports.DFG = DFG;
|
|
exports.CFG = CFG;
|
|
exports.Flags = Flags;
|
|
exports.PeepholeOptimizer = PeepholeOptimizer;
|
|
}(typeof exports === 'undefined' ? IR = {} : exports));
|
|
var c4Options = systemOptions.register(new OptionSet('C4 Options'));
|
|
var enableC4 = c4Options.register(new Option('c4', 'c4', 'boolean', false, 'Enable the C4 compiler.'));
|
|
var c4TraceLevel = c4Options.register(new Option('tc4', 'tc4', 'number', 0, 'Compiler Trace Level'));
|
|
var enableRegisterAllocator = c4Options.register(new Option('ra', 'ra', 'boolean', false, 'Enable register allocator.'));
|
|
var getPublicQualifiedName = Multiname.getPublicQualifiedName;
|
|
var createName = function createName(namespaces, name) {
|
|
if (isNumeric(name) || isObject(name)) {
|
|
return name;
|
|
}
|
|
return new Multiname(namespaces, name);
|
|
};
|
|
(function (exports) {
|
|
var Node = IR.Node;
|
|
var Start = IR.Start;
|
|
var Null = IR.Null;
|
|
var Undefined = IR.Undefined;
|
|
var This = IR.This;
|
|
var Projection = IR.Projection;
|
|
var Region = IR.Region;
|
|
var Binary = IR.Binary;
|
|
var Unary = IR.Unary;
|
|
var Constant = IR.Constant;
|
|
var Call = IR.Call;
|
|
var Phi = IR.Phi;
|
|
var Stop = IR.Stop;
|
|
var Operator = IR.Operator;
|
|
var Parameter = IR.Parameter;
|
|
var NewArray = IR.NewArray;
|
|
var NewObject = IR.NewObject;
|
|
var KeyValuePair = IR.KeyValuePair;
|
|
var isConstant = IR.isConstant;
|
|
var DFG = IR.DFG;
|
|
var CFG = IR.CFG;
|
|
var writer = new IndentingWriter();
|
|
var peepholeOptimizer = new IR.PeepholeOptimizer();
|
|
var USE_TYPE_OF_DEFAULT_ARGUMENT_CHECKING = false;
|
|
var State = function () {
|
|
var nextID = 0;
|
|
function constructor(index) {
|
|
this.id = nextID += 1;
|
|
this.index = index;
|
|
this.local = [];
|
|
this.stack = [];
|
|
this.scope = [];
|
|
this.store = Undefined;
|
|
this.loads = [];
|
|
this.saved = Undefined;
|
|
}
|
|
constructor.prototype.clone = function clone(index) {
|
|
var s = new State();
|
|
s.index = index !== undefined ? index : this.index;
|
|
s.local = this.local.slice(0);
|
|
s.stack = this.stack.slice(0);
|
|
s.scope = this.scope.slice(0);
|
|
s.loads = this.loads.slice(0);
|
|
s.saved = this.saved;
|
|
s.store = this.store;
|
|
return s;
|
|
};
|
|
constructor.prototype.matches = function matches(other) {
|
|
return this.stack.length === other.stack.length && this.scope.length === other.scope.length && this.local.length === other.local.length;
|
|
};
|
|
constructor.prototype.makeLoopPhis = function makeLoopPhis(control) {
|
|
var s = new State();
|
|
true;
|
|
function makePhi(x) {
|
|
var phi = new Phi(control, x);
|
|
phi.isLoop = true;
|
|
return phi;
|
|
}
|
|
s.index = this.index;
|
|
s.local = this.local.map(makePhi);
|
|
s.stack = this.stack.map(makePhi);
|
|
s.scope = this.scope.map(makePhi);
|
|
s.loads = this.loads.slice(0);
|
|
s.saved = this.saved;
|
|
s.store = makePhi(this.store);
|
|
return s;
|
|
};
|
|
constructor.prototype.optimize = function optimize() {
|
|
function optimize(x) {
|
|
if (x instanceof Phi && !x.isLoop) {
|
|
var args = x.args.unique();
|
|
if (args.length === 1) {
|
|
x.seal();
|
|
Counter.count('Builder: OptimizedPhi');
|
|
return args[0];
|
|
}
|
|
}
|
|
return x;
|
|
}
|
|
this.local = this.local.map(optimize);
|
|
this.stack = this.stack.map(optimize);
|
|
this.scope = this.scope.map(optimize);
|
|
this.saved = optimize(this.saved);
|
|
this.store = optimize(this.store);
|
|
};
|
|
function mergeValue(control, a, b) {
|
|
var phi = a instanceof Phi && a.control === control ? a : new Phi(control, a);
|
|
phi.pushValue(b);
|
|
return phi;
|
|
}
|
|
function mergeValues(control, a, b) {
|
|
for (var i = 0; i < a.length; i++) {
|
|
a[i] = mergeValue(control, a[i], b[i]);
|
|
}
|
|
}
|
|
constructor.prototype.merge = function merge(control, other) {
|
|
true;
|
|
true;
|
|
mergeValues(control, this.local, other.local);
|
|
mergeValues(control, this.stack, other.stack);
|
|
mergeValues(control, this.scope, other.scope);
|
|
this.store = mergeValue(control, this.store, other.store);
|
|
this.store.abstract = true;
|
|
};
|
|
constructor.prototype.trace = function trace(writer) {
|
|
writer.writeLn(this.toString());
|
|
};
|
|
function toBriefString(x) {
|
|
if (x instanceof Node) {
|
|
return x.toString(true);
|
|
}
|
|
return x;
|
|
}
|
|
constructor.prototype.toString = function () {
|
|
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);
|
|
};
|
|
return constructor;
|
|
}();
|
|
function isNumericConstant(node) {
|
|
return node instanceof Constant && isNumeric(node.value);
|
|
}
|
|
function isStringConstant(node) {
|
|
return node instanceof Constant && isString(node.value);
|
|
}
|
|
function isMultinameConstant(node) {
|
|
return node instanceof Constant && node.value instanceof Multiname;
|
|
}
|
|
function hasNumericType(node) {
|
|
if (isNumericConstant(node)) {
|
|
return true;
|
|
}
|
|
return node.ty && node.ty.isNumeric();
|
|
}
|
|
function typesAreEqual(a, b) {
|
|
if (hasNumericType(a) && hasNumericType(b) || hasStringType(a) && hasStringType(b)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function hasStringType(node) {
|
|
if (isStringConstant(node)) {
|
|
return true;
|
|
}
|
|
return node.ty && node.ty.isString();
|
|
}
|
|
function constant(value) {
|
|
return new Constant(value);
|
|
}
|
|
function qualifiedNameConstant(name) {
|
|
return constant(Multiname.getQualifiedName(name));
|
|
}
|
|
function getJSPropertyWithState(state, object, path) {
|
|
true;
|
|
var names = path.split('.');
|
|
var node = object;
|
|
for (var i = 0; i < names.length; i++) {
|
|
node = new IR.GetProperty(null, state.store, node, constant(names[i]));
|
|
node.shouldFloat = true;
|
|
state.loads.push(node);
|
|
}
|
|
return node;
|
|
}
|
|
function globalProperty(name) {
|
|
var node = new IR.GlobalProperty(name);
|
|
node.mustFloat = true;
|
|
return node;
|
|
}
|
|
function warn(message) {
|
|
}
|
|
function unary(operator, argument) {
|
|
var node = new Unary(operator, argument);
|
|
if (peepholeOptimizer) {
|
|
node = peepholeOptimizer.tryFold(node);
|
|
}
|
|
return node;
|
|
}
|
|
function binary(operator, left, right) {
|
|
var node = new Binary(operator, left, right);
|
|
if (left.ty && left.ty !== Type.Any && left.ty === right.ty) {
|
|
if (operator === Operator.EQ) {
|
|
node.operator = Operator.SEQ;
|
|
} else if (operator === Operator.NE) {
|
|
node.operator = Operator.SNE;
|
|
}
|
|
}
|
|
if (peepholeOptimizer) {
|
|
node = peepholeOptimizer.tryFold(node);
|
|
}
|
|
return node;
|
|
}
|
|
function coerceInt(value) {
|
|
return binary(Operator.OR, value, constant(0));
|
|
}
|
|
function coerceUint(value) {
|
|
return binary(Operator.URSH, value, constant(0));
|
|
}
|
|
function coerceNumber(value) {
|
|
if (hasNumericType(value)) {
|
|
return value;
|
|
}
|
|
return unary(Operator.PLUS, value);
|
|
}
|
|
function coerceBoolean(value) {
|
|
return unary(Operator.FALSE, unary(Operator.FALSE, value));
|
|
}
|
|
function shouldNotFloat(node) {
|
|
node.shouldNotFloat = true;
|
|
return node;
|
|
}
|
|
function shouldFloat(node) {
|
|
true;
|
|
node.shouldFloat = true;
|
|
return node;
|
|
}
|
|
function mustFloat(node) {
|
|
node.mustFloat = true;
|
|
return node;
|
|
}
|
|
function callPure(callee, object, args) {
|
|
return new Call(null, null, callee, object, args, IR.Flags.PRISTINE);
|
|
}
|
|
function callGlobalProperty(name, value) {
|
|
return callPure(globalProperty(name), null, [
|
|
value
|
|
]);
|
|
}
|
|
function convertString(value) {
|
|
if (isStringConstant(value)) {
|
|
return value;
|
|
}
|
|
return callPure(globalProperty('String'), null, [
|
|
value
|
|
]);
|
|
}
|
|
function coerceString(value) {
|
|
if (isStringConstant(value)) {
|
|
return value;
|
|
}
|
|
return callPure(globalProperty('asCoerceString'), null, [
|
|
value
|
|
]);
|
|
}
|
|
var coerceObject = callGlobalProperty.bind(null, 'asCoerceObject');
|
|
var coercers = createEmptyObject();
|
|
coercers[Multiname.Int] = coerceInt;
|
|
coercers[Multiname.Uint] = coerceUint;
|
|
coercers[Multiname.Number] = coerceNumber;
|
|
coercers[Multiname.String] = coerceString;
|
|
coercers[Multiname.Object] = coerceObject;
|
|
coercers[Multiname.Boolean] = coerceBoolean;
|
|
function getCoercerForType(multiname) {
|
|
true;
|
|
return coercers[Multiname.getQualifiedName(multiname)];
|
|
}
|
|
var callableConstructors = createEmptyObject();
|
|
callableConstructors[Multiname.Int] = coerceInt;
|
|
callableConstructors[Multiname.Uint] = coerceUint;
|
|
callableConstructors[Multiname.Number] = callGlobalProperty.bind(null, 'Number');
|
|
callableConstructors[Multiname.String] = callGlobalProperty.bind(null, 'String');
|
|
callableConstructors[Multiname.Object] = callGlobalProperty.bind(null, 'Object');
|
|
callableConstructors[Multiname.Boolean] = callGlobalProperty.bind(null, 'Boolean');
|
|
function getCallableConstructorForType(multiname) {
|
|
true;
|
|
return callableConstructors[Multiname.getQualifiedName(multiname)];
|
|
}
|
|
var Builder = function () {
|
|
function builder(methodInfo, scope, hasDynamicScope) {
|
|
true;
|
|
this.abc = methodInfo.abc;
|
|
this.scope = scope;
|
|
this.methodInfo = methodInfo;
|
|
this.hasDynamicScope = hasDynamicScope;
|
|
}
|
|
builder.prototype.buildStart = function (start) {
|
|
var mi = this.methodInfo;
|
|
var state = start.entryState = new State(0);
|
|
state.local.push(new This(start));
|
|
var parameterIndexOffset = this.hasDynamicScope ? 1 : 0;
|
|
var parameterCount = mi.parameters.length;
|
|
for (var i = 0; i < parameterCount; i++) {
|
|
state.local.push(new Parameter(start, parameterIndexOffset + i, mi.parameters[i].name));
|
|
}
|
|
for (var i = parameterCount; i < mi.localCount; i++) {
|
|
state.local.push(Undefined);
|
|
}
|
|
state.store = new Projection(start, Projection.Type.STORE);
|
|
if (this.hasDynamicScope) {
|
|
start.scope = new Parameter(start, 0, SAVED_SCOPE_NAME);
|
|
} else {
|
|
start.scope = new Constant(this.scope);
|
|
}
|
|
state.saved = new Projection(start, Projection.Type.SCOPE);
|
|
start.domain = new Constant(this.domain);
|
|
var args = new IR.Arguments(start);
|
|
if (mi.needsRest() || mi.needsArguments()) {
|
|
var offset = constant(parameterIndexOffset + (mi.needsRest() ? parameterCount : 0));
|
|
state.local[parameterCount + 1] = new Call(start, state.store, globalProperty('sliceArguments'), null, [
|
|
args,
|
|
offset
|
|
], IR.Flags.PRISTINE);
|
|
}
|
|
var argumentsLength = getJSPropertyWithState(state, args, 'length');
|
|
for (var i = 0; i < parameterCount; i++) {
|
|
var parameter = mi.parameters[i];
|
|
var index = i + 1;
|
|
var local = state.local[index];
|
|
if (parameter.value !== undefined) {
|
|
var condition;
|
|
if (USE_TYPE_OF_DEFAULT_ARGUMENT_CHECKING) {
|
|
condition = new IR.Binary(Operator.SEQ, new IR.Unary(Operator.TYPE_OF, local), constant('undefined'));
|
|
} else {
|
|
condition = new IR.Binary(Operator.LT, argumentsLength, constant(parameterIndexOffset + i + 1));
|
|
}
|
|
local = new IR.Latch(null, condition, constant(parameter.value), local);
|
|
}
|
|
if (parameter.type && !parameter.type.isAnyName()) {
|
|
var coercer = getCoercerForType(parameter.type);
|
|
if (coercer) {
|
|
local = coercer(local);
|
|
} else if (c4CoerceNonPrimitiveParameters) {
|
|
local = new Call(start, state.store, globalProperty('asCoerceByMultiname'), null, [
|
|
constant(this.abc.applicationDomain),
|
|
constant(parameter.type),
|
|
local
|
|
], true);
|
|
}
|
|
}
|
|
state.local[index] = local;
|
|
}
|
|
return start;
|
|
};
|
|
builder.prototype.buildGraph = function buildGraph(callerRegion, callerState, inlineArguments) {
|
|
var analysis = this.methodInfo.analysis;
|
|
var blocks = analysis.blocks;
|
|
var bytecodes = analysis.bytecodes;
|
|
var methodInfo = this.methodInfo;
|
|
var ints = this.abc.constantPool.ints;
|
|
var uints = this.abc.constantPool.uints;
|
|
var doubles = this.abc.constantPool.doubles;
|
|
var strings = this.abc.constantPool.strings;
|
|
var methods = this.abc.methods;
|
|
var classes = this.abc.classes;
|
|
var multinames = this.abc.constantPool.multinames;
|
|
var domain = new Constant(this.abc.applicationDomain);
|
|
var traceBuilder = c4TraceLevel.value > 2;
|
|
var stopPoints = [];
|
|
for (var i = 0; i < blocks.length; i++) {
|
|
blocks[i].blockDominatorOrder = i;
|
|
}
|
|
var worklist = new Shumway.SortedList(function compare(a, b) {
|
|
return a.block.blockDominatorOrder - b.block.blockDominatorOrder;
|
|
});
|
|
var start = new Start(null);
|
|
this.buildStart(start);
|
|
var createFunctionCallee = globalProperty('createFunction');
|
|
worklist.push({
|
|
region: start,
|
|
block: blocks[0]
|
|
});
|
|
var next;
|
|
while (next = worklist.pop()) {
|
|
buildBlock(next.region, next.block, next.region.entryState.clone()).forEach(function (stop) {
|
|
var target = stop.target;
|
|
var region = target.region;
|
|
if (region) {
|
|
traceBuilder && writer.enter('Merging into region: ' + region + ' @ ' + target.position + ', block ' + target.bid + ' {');
|
|
traceBuilder && writer.writeLn(' R ' + region.entryState);
|
|
traceBuilder && writer.writeLn('+ I ' + stop.state);
|
|
region.entryState.merge(region, stop.state);
|
|
region.predecessors.push(stop.control);
|
|
traceBuilder && writer.writeLn(' = ' + region.entryState);
|
|
traceBuilder && writer.leave('}');
|
|
} else {
|
|
region = target.region = new Region(stop.control);
|
|
if (target.loop) {
|
|
traceBuilder && writer.writeLn('Adding PHIs to loop region.');
|
|
}
|
|
region.entryState = target.loop ? stop.state.makeLoopPhis(region) : stop.state.clone(target.position);
|
|
traceBuilder && writer.writeLn('Adding new region: ' + region + ' @ ' + target.position + ' to worklist.');
|
|
worklist.push({
|
|
region: region,
|
|
block: target
|
|
});
|
|
}
|
|
});
|
|
traceBuilder && writer.enter('Worklist: {');
|
|
worklist.forEach(function (item) {
|
|
traceBuilder && writer.writeLn(item.region + ' ' + item.block.bdo + ' ' + item.region.entryState);
|
|
});
|
|
traceBuilder && writer.leave('}');
|
|
}
|
|
traceBuilder && writer.writeLn('Done');
|
|
function buildBlock(region, block, state) {
|
|
true;
|
|
state.optimize();
|
|
var typeState = block.entryState;
|
|
if (typeState) {
|
|
traceBuilder && writer.writeLn('Type State: ' + typeState);
|
|
for (var i = 0; i < typeState.local.length; i++) {
|
|
var type = typeState.local[i];
|
|
var local = state.local[i];
|
|
if (local.ty) {
|
|
} else {
|
|
local.ty = type;
|
|
}
|
|
}
|
|
}
|
|
var local = state.local;
|
|
var stack = state.stack;
|
|
var scope = state.scope;
|
|
function savedScope() {
|
|
return state.saved;
|
|
}
|
|
function topScope(depth) {
|
|
if (depth !== undefined) {
|
|
if (depth < scope.length) {
|
|
return scope[scope.length - 1 - depth];
|
|
} else if (depth === scope.length) {
|
|
return savedScope();
|
|
} else {
|
|
var s = savedScope();
|
|
var savedScopeDepth = depth - scope.length;
|
|
for (var i = 0; i < savedScopeDepth; i++) {
|
|
s = getJSProperty(s, 'parent');
|
|
}
|
|
return s;
|
|
}
|
|
}
|
|
if (scope.length > 0) {
|
|
return scope.top();
|
|
}
|
|
return savedScope();
|
|
}
|
|
var object, receiver, index, callee, value, multiname, type, args, pristine, left, right, operator;
|
|
function push(x) {
|
|
true;
|
|
if (bc.ti) {
|
|
if (x.ty) {
|
|
} else {
|
|
x.ty = bc.ti.type;
|
|
}
|
|
}
|
|
stack.push(x);
|
|
}
|
|
function pop() {
|
|
return stack.pop();
|
|
}
|
|
function popMany(count) {
|
|
return stack.popMany(count);
|
|
}
|
|
function pushLocal(index) {
|
|
push(local[index]);
|
|
}
|
|
function popLocal(index) {
|
|
local[index] = shouldNotFloat(pop());
|
|
}
|
|
function buildMultiname(index) {
|
|
var multiname = multinames[index];
|
|
var namespaces, name, flags = multiname.flags;
|
|
if (multiname.isRuntimeName()) {
|
|
name = stack.pop();
|
|
} else {
|
|
name = constant(multiname.name);
|
|
}
|
|
if (multiname.isRuntimeNamespace()) {
|
|
namespaces = shouldFloat(new NewArray(region, [
|
|
pop()
|
|
]));
|
|
} else {
|
|
namespaces = constant(multiname.namespaces);
|
|
}
|
|
return new IR.ASMultiname(namespaces, name, flags);
|
|
}
|
|
function simplifyName(name) {
|
|
if (isMultinameConstant(name) && Multiname.isQName(name.value)) {
|
|
return constant(Multiname.getQualifiedName(name.value));
|
|
}
|
|
return name;
|
|
}
|
|
function getGlobalScope(ti) {
|
|
if (ti && ti.object) {
|
|
return constant(ti.object);
|
|
}
|
|
return new IR.ASGlobal(null, savedScope());
|
|
}
|
|
function findProperty(multiname, strict, ti) {
|
|
var slowPath = new IR.ASFindProperty(region, state.store, topScope(), multiname, domain, strict);
|
|
if (ti) {
|
|
if (ti.object) {
|
|
if (ti.object instanceof Global && !ti.object.isExecuting()) {
|
|
warn('Can\'t optimize findProperty ' + multiname + ', global object is not yet executed or executing.');
|
|
return slowPath;
|
|
}
|
|
return constant(ti.object);
|
|
} else if (ti.scopeDepth !== undefined) {
|
|
return getScopeObject(topScope(ti.scopeDepth));
|
|
}
|
|
}
|
|
warn('Can\'t optimize findProperty ' + multiname);
|
|
return slowPath;
|
|
}
|
|
function getJSProperty(object, path) {
|
|
return getJSPropertyWithState(state, object, path);
|
|
}
|
|
function coerce(multiname, value) {
|
|
if (false && isConstant(value)) {
|
|
return constant(asCoerceByMultiname(domain.value, multiname, value.value));
|
|
} else {
|
|
var coercer = getCoercerForType(multiname);
|
|
if (coercer) {
|
|
return coercer(value);
|
|
}
|
|
}
|
|
if (c4CoerceNonPrimitive) {
|
|
return call(globalProperty('asCoerceByMultiname'), null, [
|
|
domain,
|
|
constant(multiname),
|
|
value
|
|
]);
|
|
}
|
|
return value;
|
|
}
|
|
function getScopeObject(scope) {
|
|
if (scope instanceof IR.ASScope) {
|
|
return scope.object;
|
|
}
|
|
return getJSProperty(scope, 'object');
|
|
}
|
|
function store(node) {
|
|
state.store = new Projection(node, Projection.Type.STORE);
|
|
node.loads = state.loads.slice(0);
|
|
state.loads.length = 0;
|
|
return node;
|
|
}
|
|
function load(node) {
|
|
state.loads.push(node);
|
|
return node;
|
|
}
|
|
function resolveMultinameGlobally(multiname) {
|
|
var namespaces = multiname.namespaces;
|
|
var name = multiname.name;
|
|
if (!Shumway.AVM2.Runtime.globalMultinameAnalysis.value) {
|
|
return;
|
|
}
|
|
if (!isConstant(namespaces) || !isConstant(name) || multiname.isAttribute()) {
|
|
Counter.count('GlobalMultinameResolver: Cannot resolve runtime multiname or attribute.');
|
|
return;
|
|
}
|
|
if (isNumeric(name.value) || !isString(name.value) || !name.value) {
|
|
Counter.count('GlobalMultinameResolver: Cannot resolve numeric or any names.');
|
|
return false;
|
|
}
|
|
return GlobalMultinameResolver.resolveMultiname(new Multiname(namespaces.value, name.value, multiname.flags));
|
|
}
|
|
function callSuper(scope, object, multiname, args, ti) {
|
|
if (ti && ti.trait && ti.trait.isMethod() && ti.baseClass) {
|
|
var qn = VM_OPEN_METHOD_PREFIX + Multiname.getQualifiedName(ti.trait.name);
|
|
var callee = getJSProperty(constant(ti.baseClass), 'traitsPrototype.' + qn);
|
|
return call(callee, object, args);
|
|
}
|
|
return store(new IR.ASCallSuper(region, state.store, object, multiname, args, IR.Flags.PRISTINE, scope));
|
|
}
|
|
function getSuper(scope, object, multiname, ti) {
|
|
if (ti && ti.trait && ti.trait.isGetter() && ti.baseClass) {
|
|
var qn = VM_OPEN_GET_METHOD_PREFIX + Multiname.getQualifiedName(ti.trait.name);
|
|
var callee = getJSProperty(constant(ti.baseClass), 'traitsPrototype.' + qn);
|
|
return call(callee, object, []);
|
|
}
|
|
return store(new IR.ASGetSuper(region, state.store, object, multiname, scope));
|
|
}
|
|
function setSuper(scope, object, multiname, value, ti) {
|
|
if (ti && ti.trait && ti.trait.isSetter() && ti.baseClass) {
|
|
var qn = VM_OPEN_SET_METHOD_PREFIX + Multiname.getQualifiedName(ti.trait.name);
|
|
var callee = getJSProperty(constant(ti.baseClass), 'traitsPrototype.' + qn);
|
|
return call(callee, object, [
|
|
value
|
|
]);
|
|
}
|
|
return store(new IR.ASSetSuper(region, state.store, object, multiname, value, scope));
|
|
}
|
|
function constructSuper(scope, object, args, ti) {
|
|
if (ti) {
|
|
if (ti.noCallSuperNeeded) {
|
|
return;
|
|
} else if (ti.baseClass) {
|
|
var callee = getJSProperty(constant(ti.baseClass), 'instanceConstructorNoInitialize');
|
|
call(callee, object, args);
|
|
return;
|
|
}
|
|
}
|
|
callee = getJSProperty(scope, 'object.baseClass.instanceConstructorNoInitialize');
|
|
call(callee, object, args);
|
|
return;
|
|
}
|
|
function callProperty(object, multiname, args, isLex, ti) {
|
|
if (ti && ti.trait) {
|
|
if (ti.trait.isMethod()) {
|
|
var openQn;
|
|
if (ti.trait.holder instanceof InstanceInfo && ti.trait.holder.isInterface()) {
|
|
openQn = Multiname.getPublicQualifiedName(Multiname.getName(ti.trait.name));
|
|
} else {
|
|
openQn = Multiname.getQualifiedName(ti.trait.name);
|
|
}
|
|
openQn = VM_OPEN_METHOD_PREFIX + openQn;
|
|
return store(new IR.CallProperty(region, state.store, object, constant(openQn), args, IR.Flags.PRISTINE));
|
|
} else if (ti.trait.isClass()) {
|
|
var constructor = getCallableConstructorForType(ti.trait.name);
|
|
if (constructor) {
|
|
return constructor(args[0]);
|
|
}
|
|
var qn = Multiname.getQualifiedName(ti.trait.name);
|
|
return store(new IR.CallProperty(region, state.store, object, constant(qn), args, 0));
|
|
}
|
|
} else if (ti && ti.propertyQName) {
|
|
return store(new IR.CallProperty(region, state.store, object, constant(ti.propertyQName), args, IR.Flags.PRISTINE));
|
|
}
|
|
var qn = resolveMultinameGlobally(multiname);
|
|
if (qn) {
|
|
return store(new IR.ASCallProperty(region, state.store, object, constant(Multiname.getQualifiedName(qn)), args, IR.Flags.PRISTINE | IR.Flags.RESOLVED, isLex));
|
|
}
|
|
return store(new IR.ASCallProperty(region, state.store, object, multiname, args, IR.Flags.PRISTINE, isLex));
|
|
}
|
|
function getProperty(object, multiname, ti, getOpenMethod) {
|
|
true;
|
|
getOpenMethod = !(!getOpenMethod);
|
|
if (ti) {
|
|
if (ti.trait) {
|
|
if (ti.trait.isConst() && ti.trait.hasDefaultValue) {
|
|
return constant(ti.trait.value);
|
|
}
|
|
var get = new IR.GetProperty(region, state.store, object, qualifiedNameConstant(ti.trait.name));
|
|
return ti.trait.isGetter() ? store(get) : load(get);
|
|
}
|
|
if (ti.propertyQName) {
|
|
return store(new IR.GetProperty(region, state.store, object, constant(ti.propertyQName)));
|
|
} else if (ti.isDirectlyReadable) {
|
|
return store(new IR.GetProperty(region, state.store, object, multiname.name));
|
|
} else if (ti.isIndexedReadable) {
|
|
return store(new IR.ASGetProperty(region, state.store, object, multiname, IR.Flags.INDEXED | (getOpenMethod ? IR.Flagas.IS_METHOD : 0)));
|
|
}
|
|
}
|
|
warn('Can\'t optimize getProperty ' + multiname);
|
|
var qn = resolveMultinameGlobally(multiname);
|
|
if (qn) {
|
|
return store(new IR.ASGetProperty(region, state.store, object, constant(Multiname.getQualifiedName(qn)), IR.Flags.RESOLVED | (getOpenMethod ? IR.Flagas.IS_METHOD : 0)));
|
|
}
|
|
Counter.count('Compiler: Slow ASGetProperty');
|
|
return store(new IR.ASGetProperty(region, state.store, object, multiname, getOpenMethod ? IR.Flagas.IS_METHOD : 0));
|
|
}
|
|
function setProperty(object, multiname, value, ti) {
|
|
true;
|
|
if (ti) {
|
|
if (ti.trait) {
|
|
var coercer = ti.trait.typeName ? getCoercerForType(ti.trait.typeName) : null;
|
|
if (coercer) {
|
|
value = coercer(value);
|
|
}
|
|
store(new IR.SetProperty(region, state.store, object, qualifiedNameConstant(ti.trait.name), value));
|
|
return;
|
|
}
|
|
if (ti.propertyQName) {
|
|
return store(new IR.SetProperty(region, state.store, object, constant(ti.propertyQName), value));
|
|
} else if (ti.isDirectlyWriteable) {
|
|
return store(new IR.SetProperty(region, state.store, object, multiname.name, value));
|
|
} else if (ti.isIndexedWriteable) {
|
|
return store(new IR.ASSetProperty(region, state.store, object, multiname, value, IR.Flags.INDEXED));
|
|
}
|
|
}
|
|
warn('Can\'t optimize setProperty ' + multiname);
|
|
var qn = resolveMultinameGlobally(multiname);
|
|
if (qn) {
|
|
}
|
|
return store(new IR.ASSetProperty(region, state.store, object, multiname, value, 0));
|
|
}
|
|
function getDescendants(object, name, ti) {
|
|
name = simplifyName(name);
|
|
return new IR.ASGetDescendants(region, state.store, object, name);
|
|
}
|
|
function getSlot(object, index, ti) {
|
|
if (ti) {
|
|
var trait = ti.trait;
|
|
if (trait) {
|
|
if (trait.isConst() && ti.trait.hasDefaultValue) {
|
|
return constant(trait.value);
|
|
}
|
|
var slotQn = Multiname.getQualifiedName(trait.name);
|
|
return store(new IR.GetProperty(region, state.store, object, constant(slotQn)));
|
|
}
|
|
}
|
|
warn('Can\'t optimize getSlot ' + index);
|
|
return store(new IR.ASGetSlot(null, state.store, object, index));
|
|
}
|
|
function setSlot(object, index, value, ti) {
|
|
if (ti) {
|
|
var trait = ti.trait;
|
|
if (trait) {
|
|
var slotQn = Multiname.getQualifiedName(trait.name);
|
|
store(new IR.SetProperty(region, state.store, object, constant(slotQn), value));
|
|
return;
|
|
}
|
|
}
|
|
warn('Can\'t optimize setSlot ' + index);
|
|
store(new IR.ASSetSlot(region, state.store, object, index, value));
|
|
}
|
|
function call(callee, object, args) {
|
|
return store(new Call(region, state.store, callee, object, args, IR.Flags.PRISTINE));
|
|
}
|
|
function callCall(callee, object, args, pristine) {
|
|
return store(new Call(region, state.store, callee, object, args, pristine ? IR.Flags.PRISTINE : 0));
|
|
}
|
|
function truthyCondition(operator) {
|
|
var right;
|
|
if (operator.isBinary()) {
|
|
right = pop();
|
|
}
|
|
var left = pop();
|
|
var node;
|
|
if (right) {
|
|
node = binary(operator, left, right);
|
|
} else {
|
|
node = unary(operator, left);
|
|
}
|
|
if (peepholeOptimizer) {
|
|
node = peepholeOptimizer.tryFold(node, true);
|
|
}
|
|
return node;
|
|
}
|
|
function negatedTruthyCondition(operator) {
|
|
var node = unary(Operator.FALSE, truthyCondition(operator));
|
|
if (peepholeOptimizer) {
|
|
node = peepholeOptimizer.tryFold(node, true);
|
|
}
|
|
return node;
|
|
}
|
|
function pushExpression(operator, toInt) {
|
|
var left, right;
|
|
if (operator.isBinary()) {
|
|
right = pop();
|
|
left = pop();
|
|
if (toInt) {
|
|
right = coerceInt(right);
|
|
left = coerceInt(left);
|
|
}
|
|
push(binary(operator, left, right));
|
|
} else {
|
|
left = pop();
|
|
if (toInt) {
|
|
left = coerceInt(left);
|
|
}
|
|
push(unary(operator, left));
|
|
}
|
|
}
|
|
var stops = null;
|
|
function buildIfStops(predicate) {
|
|
true;
|
|
var _if = new IR.If(region, predicate);
|
|
stops = [
|
|
{
|
|
control: new Projection(_if, Projection.Type.FALSE),
|
|
target: bytecodes[bc.position + 1],
|
|
state: state
|
|
},
|
|
{
|
|
control: new Projection(_if, Projection.Type.TRUE),
|
|
target: bc.target,
|
|
state: state
|
|
}
|
|
];
|
|
}
|
|
function buildJumpStop() {
|
|
true;
|
|
stops = [
|
|
{
|
|
control: region,
|
|
target: bc.target,
|
|
state: state
|
|
}
|
|
];
|
|
}
|
|
function buildThrowStop() {
|
|
true;
|
|
stops = [];
|
|
}
|
|
function buildReturnStop() {
|
|
true;
|
|
stops = [];
|
|
}
|
|
function buildSwitchStops(determinant) {
|
|
true;
|
|
if (bc.targets.length > 2) {
|
|
stops = [];
|
|
var _switch = new IR.Switch(region, determinant);
|
|
for (var i = 0; i < bc.targets.length; i++) {
|
|
stops.push({
|
|
control: new Projection(_switch, Projection.Type.CASE, constant(i)),
|
|
target: bc.targets[i],
|
|
state: state
|
|
});
|
|
}
|
|
} else {
|
|
true;
|
|
var predicate = binary(Operator.SEQ, determinant, constant(0));
|
|
var _if = new IR.If(region, predicate);
|
|
stops = [
|
|
{
|
|
control: new Projection(_if, Projection.Type.FALSE),
|
|
target: bc.targets[1],
|
|
state: state
|
|
},
|
|
{
|
|
control: new Projection(_if, Projection.Type.TRUE),
|
|
target: bc.targets[0],
|
|
state: state
|
|
}
|
|
];
|
|
}
|
|
}
|
|
if (traceBuilder) {
|
|
writer.writeLn('Processing Region: ' + region + ', Block: ' + block.bid);
|
|
writer.enter(('> state: ' + region.entryState.toString()).padRight(' ', 100));
|
|
}
|
|
region.processed = true;
|
|
var bc;
|
|
for (var bci = block.position, end = block.end.position; bci <= end; bci++) {
|
|
bc = bytecodes[bci];
|
|
var op = bc.op;
|
|
state.index = bci;
|
|
switch (op) {
|
|
case 3:
|
|
store(new IR.Throw(region, pop()));
|
|
stopPoints.push({
|
|
region: region,
|
|
store: state.store,
|
|
value: Undefined
|
|
});
|
|
buildThrowStop();
|
|
break;
|
|
case 98:
|
|
pushLocal(bc.index);
|
|
break;
|
|
case 208:
|
|
case 209:
|
|
case 210:
|
|
case 211:
|
|
pushLocal(op - OP_getlocal0);
|
|
break;
|
|
case 99:
|
|
popLocal(bc.index);
|
|
break;
|
|
case 212:
|
|
case 213:
|
|
case 214:
|
|
case 215:
|
|
popLocal(op - OP_setlocal0);
|
|
break;
|
|
case 28:
|
|
scope.push(new IR.ASScope(topScope(), pop(), true));
|
|
break;
|
|
case 48:
|
|
scope.push(new IR.ASScope(topScope(), pop(), false));
|
|
break;
|
|
case 29:
|
|
scope.pop();
|
|
break;
|
|
case 100:
|
|
push(getGlobalScope(bc.ti));
|
|
break;
|
|
case 101:
|
|
push(getScopeObject(state.scope[bc.index]));
|
|
break;
|
|
case 93:
|
|
push(findProperty(buildMultiname(bc.index), true, bc.ti));
|
|
break;
|
|
case 94:
|
|
push(findProperty(buildMultiname(bc.index), false, bc.ti));
|
|
break;
|
|
case 102:
|
|
multiname = buildMultiname(bc.index);
|
|
object = pop();
|
|
push(getProperty(object, multiname, bc.ti, false));
|
|
break;
|
|
case 89:
|
|
multiname = buildMultiname(bc.index);
|
|
object = pop();
|
|
push(getDescendants(object, multiname, bc.ti));
|
|
break;
|
|
case 96:
|
|
multiname = buildMultiname(bc.index);
|
|
push(getProperty(findProperty(multiname, true, bc.ti), multiname, bc.ti, false));
|
|
break;
|
|
case 104:
|
|
case 97:
|
|
value = pop();
|
|
multiname = buildMultiname(bc.index);
|
|
object = pop();
|
|
setProperty(object, multiname, value, bc.ti);
|
|
break;
|
|
case 106:
|
|
multiname = buildMultiname(bc.index);
|
|
object = pop();
|
|
push(store(new IR.ASDeleteProperty(region, state.store, object, multiname)));
|
|
break;
|
|
case 108:
|
|
object = pop();
|
|
push(getSlot(object, constant(bc.index), bc.ti));
|
|
break;
|
|
case 109:
|
|
value = pop();
|
|
object = pop();
|
|
setSlot(object, constant(bc.index), value, bc.ti);
|
|
break;
|
|
case 4:
|
|
multiname = buildMultiname(bc.index);
|
|
object = pop();
|
|
push(getSuper(savedScope(), object, multiname, bc.ti));
|
|
break;
|
|
case 5:
|
|
value = pop();
|
|
multiname = buildMultiname(bc.index);
|
|
object = pop();
|
|
setSuper(savedScope(), object, multiname, value, bc.ti);
|
|
break;
|
|
case 241:
|
|
case 240:
|
|
break;
|
|
case 64:
|
|
push(callPure(createFunctionCallee, null, [
|
|
constant(methods[bc.index]),
|
|
topScope(),
|
|
constant(true)
|
|
]));
|
|
break;
|
|
case 65:
|
|
args = popMany(bc.argCount);
|
|
object = pop();
|
|
callee = pop();
|
|
push(callCall(callee, object, args));
|
|
break;
|
|
case 70:
|
|
case 79:
|
|
case 76:
|
|
args = popMany(bc.argCount);
|
|
multiname = buildMultiname(bc.index);
|
|
object = pop();
|
|
value = callProperty(object, multiname, args, op === OP_callproplex, bc.ti);
|
|
if (op !== OP_callpropvoid) {
|
|
push(value);
|
|
}
|
|
break;
|
|
case 69:
|
|
case 78:
|
|
multiname = buildMultiname(bc.index);
|
|
args = popMany(bc.argCount);
|
|
object = pop();
|
|
value = callSuper(savedScope(), object, multiname, args, bc.ti);
|
|
if (op !== OP_callsupervoid) {
|
|
push(value);
|
|
}
|
|
break;
|
|
case 66:
|
|
args = popMany(bc.argCount);
|
|
object = pop();
|
|
push(store(new IR.ASNew(region, state.store, object, args)));
|
|
break;
|
|
case 73:
|
|
args = popMany(bc.argCount);
|
|
object = pop();
|
|
constructSuper(savedScope(), object, args, bc.ti);
|
|
break;
|
|
case 74:
|
|
args = popMany(bc.argCount);
|
|
multiname = buildMultiname(bc.index);
|
|
object = pop();
|
|
callee = getProperty(object, multiname, bc.ti, false);
|
|
push(store(new IR.ASNew(region, state.store, callee, args)));
|
|
break;
|
|
case 128:
|
|
if (bc.ti && bc.ti.noCoercionNeeded) {
|
|
Counter.count('Compiler: NoCoercionNeeded');
|
|
break;
|
|
} else {
|
|
Counter.count('Compiler: CoercionNeeded');
|
|
}
|
|
value = pop();
|
|
push(coerce(multinames[bc.index], value));
|
|
break;
|
|
case 131:
|
|
case 115:
|
|
push(coerceInt(pop()));
|
|
break;
|
|
case 136:
|
|
case 116:
|
|
push(coerceUint(pop()));
|
|
break;
|
|
case 132:
|
|
case 117:
|
|
push(coerceNumber(pop()));
|
|
break;
|
|
case 129:
|
|
case 118:
|
|
push(coerceBoolean(pop()));
|
|
break;
|
|
case 120:
|
|
push(call(globalProperty('checkFilter'), null, [
|
|
pop()
|
|
]));
|
|
break;
|
|
case 130:
|
|
break;
|
|
case 133:
|
|
push(coerceString(pop()));
|
|
break;
|
|
case 112:
|
|
push(convertString(pop()));
|
|
break;
|
|
case 135:
|
|
type = pop();
|
|
if (c4AsTypeLate) {
|
|
value = pop();
|
|
push(call(globalProperty('asAsType'), null, [
|
|
type,
|
|
value
|
|
]));
|
|
}
|
|
break;
|
|
case 72:
|
|
case 71:
|
|
value = Undefined;
|
|
if (op === OP_returnvalue) {
|
|
value = pop();
|
|
if (methodInfo.returnType) {
|
|
if (!(bc.ti && bc.ti.noCoercionNeeded)) {
|
|
value = coerce(methodInfo.returnType, value);
|
|
}
|
|
}
|
|
}
|
|
stopPoints.push({
|
|
region: region,
|
|
store: state.store,
|
|
value: value
|
|
});
|
|
buildReturnStop();
|
|
break;
|
|
case 30:
|
|
case 35:
|
|
index = pop();
|
|
object = pop();
|
|
push(new IR.CallProperty(region, state.store, object, constant(op === OP_nextname ? 'asNextName' : 'asNextValue'), [
|
|
index
|
|
], IR.Flags.PRISTINE));
|
|
break;
|
|
case 50:
|
|
var temp = call(globalProperty('asHasNext2'), null, [
|
|
local[bc.object],
|
|
local[bc.index]
|
|
]);
|
|
local[bc.object] = getJSProperty(temp, 'object');
|
|
push(local[bc.index] = getJSProperty(temp, 'index'));
|
|
break;
|
|
case 32:
|
|
push(Null);
|
|
break;
|
|
case 33:
|
|
push(Undefined);
|
|
break;
|
|
case 34:
|
|
notImplemented();
|
|
break;
|
|
case 36:
|
|
push(constant(bc.value));
|
|
break;
|
|
case 37:
|
|
push(constant(bc.value));
|
|
break;
|
|
case 44:
|
|
push(constant(strings[bc.index]));
|
|
break;
|
|
case 45:
|
|
push(constant(ints[bc.index]));
|
|
break;
|
|
case 46:
|
|
push(constant(uints[bc.index]));
|
|
break;
|
|
case 47:
|
|
push(constant(doubles[bc.index]));
|
|
break;
|
|
case 38:
|
|
push(constant(true));
|
|
break;
|
|
case 39:
|
|
push(constant(false));
|
|
break;
|
|
case 40:
|
|
push(constant(NaN));
|
|
break;
|
|
case 41:
|
|
pop();
|
|
break;
|
|
case 42:
|
|
value = shouldNotFloat(pop());
|
|
push(value);
|
|
push(value);
|
|
break;
|
|
case 43:
|
|
state.stack.push(pop(), pop());
|
|
break;
|
|
case 239:
|
|
case OP_debugline:
|
|
case OP_debugfile:
|
|
break;
|
|
case 12:
|
|
buildIfStops(negatedTruthyCondition(Operator.LT));
|
|
break;
|
|
case 24:
|
|
buildIfStops(truthyCondition(Operator.GE));
|
|
break;
|
|
case 13:
|
|
buildIfStops(negatedTruthyCondition(Operator.LE));
|
|
break;
|
|
case 23:
|
|
buildIfStops(truthyCondition(Operator.GT));
|
|
break;
|
|
case 14:
|
|
buildIfStops(negatedTruthyCondition(Operator.GT));
|
|
break;
|
|
case 22:
|
|
buildIfStops(truthyCondition(Operator.LE));
|
|
break;
|
|
case 15:
|
|
buildIfStops(negatedTruthyCondition(Operator.GE));
|
|
break;
|
|
case 21:
|
|
buildIfStops(truthyCondition(Operator.LT));
|
|
break;
|
|
case 16:
|
|
buildJumpStop();
|
|
break;
|
|
case 17:
|
|
buildIfStops(truthyCondition(Operator.TRUE));
|
|
break;
|
|
case 18:
|
|
buildIfStops(truthyCondition(Operator.FALSE));
|
|
break;
|
|
case 19:
|
|
buildIfStops(truthyCondition(Operator.EQ));
|
|
break;
|
|
case 20:
|
|
buildIfStops(truthyCondition(Operator.NE));
|
|
break;
|
|
case 25:
|
|
buildIfStops(truthyCondition(Operator.SEQ));
|
|
break;
|
|
case 26:
|
|
buildIfStops(truthyCondition(Operator.SNE));
|
|
break;
|
|
case 27:
|
|
buildSwitchStops(pop());
|
|
break;
|
|
case 150:
|
|
pushExpression(Operator.FALSE);
|
|
break;
|
|
case 151:
|
|
pushExpression(Operator.BITWISE_NOT);
|
|
break;
|
|
case 160:
|
|
right = pop();
|
|
left = pop();
|
|
if (typesAreEqual(left, right)) {
|
|
operator = Operator.ADD;
|
|
} else if (Shumway.AVM2.Runtime.useAsAdd) {
|
|
operator = Operator.AS_ADD;
|
|
} else {
|
|
operator = Operator.ADD;
|
|
}
|
|
push(binary(operator, left, right));
|
|
break;
|
|
case 197:
|
|
pushExpression(Operator.ADD, true);
|
|
break;
|
|
case 161:
|
|
pushExpression(Operator.SUB);
|
|
break;
|
|
case 198:
|
|
pushExpression(Operator.SUB, true);
|
|
break;
|
|
case 162:
|
|
pushExpression(Operator.MUL);
|
|
break;
|
|
case 199:
|
|
pushExpression(Operator.MUL, true);
|
|
break;
|
|
case 163:
|
|
pushExpression(Operator.DIV);
|
|
break;
|
|
case 164:
|
|
pushExpression(Operator.MOD);
|
|
break;
|
|
case 165:
|
|
pushExpression(Operator.LSH);
|
|
break;
|
|
case 166:
|
|
pushExpression(Operator.RSH);
|
|
break;
|
|
case 167:
|
|
pushExpression(Operator.URSH);
|
|
break;
|
|
case 168:
|
|
pushExpression(Operator.AND);
|
|
break;
|
|
case 169:
|
|
pushExpression(Operator.OR);
|
|
break;
|
|
case 170:
|
|
pushExpression(Operator.XOR);
|
|
break;
|
|
case 171:
|
|
pushExpression(Operator.EQ);
|
|
break;
|
|
case 172:
|
|
pushExpression(Operator.SEQ);
|
|
break;
|
|
case 173:
|
|
pushExpression(Operator.LT);
|
|
break;
|
|
case 174:
|
|
pushExpression(Operator.LE);
|
|
break;
|
|
case 175:
|
|
pushExpression(Operator.GT);
|
|
break;
|
|
case 176:
|
|
pushExpression(Operator.GE);
|
|
break;
|
|
case 144:
|
|
pushExpression(Operator.NEG);
|
|
break;
|
|
case 196:
|
|
pushExpression(Operator.NEG, true);
|
|
break;
|
|
case 145:
|
|
case 192:
|
|
case 147:
|
|
case 193:
|
|
push(constant(1));
|
|
if (op === OP_increment || op === OP_decrement) {
|
|
push(coerceNumber(pop()));
|
|
} else {
|
|
push(coerceInt(pop()));
|
|
}
|
|
if (op === OP_increment || op === OP_increment_i) {
|
|
pushExpression(Operator.ADD);
|
|
} else {
|
|
pushExpression(Operator.SUB);
|
|
}
|
|
break;
|
|
case 146:
|
|
case 194:
|
|
case 148:
|
|
case 195:
|
|
push(constant(1));
|
|
if (op === OP_inclocal || op === OP_declocal) {
|
|
push(coerceNumber(local[bc.index]));
|
|
} else {
|
|
push(coerceInt(local[bc.index]));
|
|
}
|
|
if (op === OP_inclocal || op === OP_inclocal_i) {
|
|
pushExpression(Operator.ADD);
|
|
} else {
|
|
pushExpression(Operator.SUB);
|
|
}
|
|
popLocal(bc.index);
|
|
break;
|
|
case 177:
|
|
type = pop();
|
|
value = pop();
|
|
push(call(getJSProperty(type, 'isInstanceOf'), null, [
|
|
value
|
|
]));
|
|
break;
|
|
case 178:
|
|
value = pop();
|
|
multiname = buildMultiname(bc.index);
|
|
type = getProperty(findProperty(multiname, false), multiname);
|
|
push(call(globalProperty('asIsType'), null, [
|
|
type,
|
|
value
|
|
]));
|
|
break;
|
|
case 179:
|
|
type = pop();
|
|
value = pop();
|
|
push(call(globalProperty('asIsType'), null, [
|
|
type,
|
|
value
|
|
]));
|
|
break;
|
|
case 180:
|
|
object = pop();
|
|
value = pop();
|
|
multiname = new IR.ASMultiname(Undefined, value, 0);
|
|
push(store(new IR.ASHasProperty(region, state.store, object, multiname)));
|
|
break;
|
|
case 149:
|
|
push(call(globalProperty('asTypeOf'), null, [
|
|
pop()
|
|
]));
|
|
break;
|
|
case 8:
|
|
push(Undefined);
|
|
popLocal(bc.index);
|
|
break;
|
|
case 83:
|
|
args = popMany(bc.argCount);
|
|
type = pop();
|
|
callee = globalProperty('applyType');
|
|
push(call(callee, null, [
|
|
domain,
|
|
type,
|
|
new NewArray(region, args)
|
|
]));
|
|
break;
|
|
case 86:
|
|
args = popMany(bc.argCount);
|
|
push(new NewArray(region, args));
|
|
break;
|
|
case 85:
|
|
var properties = [];
|
|
for (var i = 0; i < bc.argCount; i++) {
|
|
var value = pop();
|
|
var key = pop();
|
|
true;
|
|
key = constant(Multiname.getPublicQualifiedName(key.value));
|
|
properties.push(new KeyValuePair(key, value));
|
|
}
|
|
push(new NewObject(region, properties));
|
|
break;
|
|
case 87:
|
|
push(new IR.ASNewActivation(constant(methodInfo)));
|
|
break;
|
|
case 88:
|
|
callee = globalProperty('createClass');
|
|
push(call(callee, null, [
|
|
constant(classes[bc.index]),
|
|
pop(),
|
|
topScope()
|
|
]));
|
|
break;
|
|
default:
|
|
unexpected('Not Implemented: ' + bc);
|
|
}
|
|
if (op === OP_debug || op === OP_debugfile || op === OP_debugline) {
|
|
continue;
|
|
}
|
|
if (traceBuilder) {
|
|
writer.writeLn(('state: ' + state.toString()).padRight(' ', 100) + ' : ' + bci + ', ' + bc.toString(this.abc));
|
|
}
|
|
}
|
|
if (traceBuilder) {
|
|
writer.leave(('< state: ' + state.toString()).padRight(' ', 100));
|
|
}
|
|
if (!stops) {
|
|
stops = [];
|
|
if (bc.position + 1 <= bytecodes.length) {
|
|
stops.push({
|
|
control: region,
|
|
target: bytecodes[bc.position + 1],
|
|
state: state
|
|
});
|
|
}
|
|
}
|
|
return stops;
|
|
}
|
|
var stop;
|
|
if (stopPoints.length > 1) {
|
|
var stopRegion = new Region(null);
|
|
var stopValuePhi = new Phi(stopRegion, null);
|
|
var stopStorePhi = new Phi(stopRegion, null);
|
|
stopPoints.forEach(function (stopPoint) {
|
|
stopRegion.predecessors.push(stopPoint.region);
|
|
stopValuePhi.pushValue(stopPoint.value);
|
|
stopStorePhi.pushValue(stopPoint.store);
|
|
});
|
|
stop = new Stop(stopRegion, stopStorePhi, stopValuePhi);
|
|
} else {
|
|
stop = new Stop(stopPoints[0].region, stopPoints[0].store, stopPoints[0].value);
|
|
}
|
|
return new DFG(stop);
|
|
};
|
|
return builder;
|
|
}();
|
|
function buildMethod(verifier, methodInfo, scope, hasDynamicScope) {
|
|
true;
|
|
true;
|
|
true;
|
|
Counter.count('Compiler: Compiled Methods');
|
|
Timer.start('Compiler');
|
|
Timer.start('Mark Loops');
|
|
methodInfo.analysis.markLoops();
|
|
Timer.stop();
|
|
if (Shumway.AVM2.Runtime.enableVerifier.value) {
|
|
Timer.start('Verify');
|
|
verifier.verifyMethod(methodInfo, scope);
|
|
Timer.stop();
|
|
}
|
|
var traceSource = c4TraceLevel.value > 0;
|
|
var traceIR = c4TraceLevel.value > 1;
|
|
Timer.start('Build IR');
|
|
Node.startNumbering();
|
|
var dfg = new Builder(methodInfo, scope, hasDynamicScope).buildGraph();
|
|
Timer.stop();
|
|
traceIR && dfg.trace(writer);
|
|
Timer.start('Build CFG');
|
|
var cfg = dfg.buildCFG();
|
|
Timer.stop();
|
|
Timer.start('Optimize Phis');
|
|
cfg.optimizePhis();
|
|
Timer.stop();
|
|
Timer.start('Schedule Nodes');
|
|
cfg.scheduleEarly();
|
|
Timer.stop();
|
|
traceIR && cfg.trace(writer);
|
|
Timer.start('Verify IR');
|
|
cfg.verify();
|
|
Timer.stop();
|
|
Timer.start('Allocate Variables');
|
|
cfg.allocateVariables();
|
|
Timer.stop();
|
|
Timer.start('Generate Source');
|
|
var result = Backend.generate(cfg, enableRegisterAllocator.value);
|
|
Timer.stop();
|
|
traceSource && writer.writeLn(result.body);
|
|
Node.stopNumbering();
|
|
Timer.stop();
|
|
return result;
|
|
}
|
|
exports.buildMethod = buildMethod;
|
|
}(typeof exports === 'undefined' ? Builder = {} : exports));
|
|
var Compiler = new (function () {
|
|
function constructor() {
|
|
this.verifier = new Verifier();
|
|
}
|
|
constructor.prototype.compileMethod = function (methodInfo, scope, hasDynamicScope) {
|
|
return Builder.buildMethod(this.verifier, methodInfo, scope, hasDynamicScope);
|
|
};
|
|
return constructor;
|
|
}())();
|
|
(function (exports) {
|
|
var Control = function () {
|
|
var SEQ = 1;
|
|
var LOOP = 2;
|
|
var IF = 3;
|
|
var CASE = 4;
|
|
var SWITCH = 5;
|
|
var LABEL_CASE = 6;
|
|
var LABEL_SWITCH = 7;
|
|
var EXIT = 8;
|
|
var BREAK = 9;
|
|
var CONTINUE = 10;
|
|
var TRY = 11;
|
|
var CATCH = 12;
|
|
function Seq(body) {
|
|
this.kind = SEQ;
|
|
this.body = body;
|
|
}
|
|
Seq.prototype = {
|
|
trace: function (writer) {
|
|
var body = this.body;
|
|
for (var i = 0, j = body.length; i < j; i++) {
|
|
body[i].trace(writer);
|
|
}
|
|
},
|
|
first: function () {
|
|
return this.body[0];
|
|
},
|
|
slice: function (begin, end) {
|
|
return new Seq(this.body.slice(begin, end));
|
|
}
|
|
};
|
|
function Loop(body) {
|
|
this.kind = LOOP;
|
|
this.body = body;
|
|
}
|
|
Loop.prototype = {
|
|
trace: function (writer) {
|
|
writer.enter('loop {');
|
|
this.body.trace(writer);
|
|
writer.leave('}');
|
|
}
|
|
};
|
|
function If(cond, then, els, nothingThrownLabel) {
|
|
this.kind = IF;
|
|
this.cond = cond;
|
|
this.then = then;
|
|
this.else = els;
|
|
this.negated = false;
|
|
this.nothingThrownLabel = nothingThrownLabel;
|
|
}
|
|
If.prototype = {
|
|
trace: function (writer) {
|
|
this.cond.trace(writer);
|
|
if (this.nothingThrownLabel) {
|
|
writer.enter('if (label is ' + this.nothingThrownLabel + ') {');
|
|
}
|
|
writer.enter('if' + (this.negated ? ' not' : '') + ' {');
|
|
this.then && this.then.trace(writer);
|
|
if (this.else) {
|
|
writer.outdent();
|
|
writer.enter('} else {');
|
|
this.else.trace(writer);
|
|
}
|
|
writer.leave('}');
|
|
if (this.nothingThrownLabel) {
|
|
writer.leave('}');
|
|
}
|
|
}
|
|
};
|
|
function Case(index, body) {
|
|
this.kind = CASE;
|
|
this.index = index;
|
|
this.body = body;
|
|
}
|
|
Case.prototype = {
|
|
trace: function (writer) {
|
|
if (this.index >= 0) {
|
|
writer.writeLn('case ' + this.index + ':');
|
|
} else {
|
|
writer.writeLn('default:');
|
|
}
|
|
writer.indent();
|
|
this.body && this.body.trace(writer);
|
|
writer.outdent();
|
|
}
|
|
};
|
|
function Switch(determinant, cases, nothingThrownLabel) {
|
|
this.kind = SWITCH;
|
|
this.determinant = determinant;
|
|
this.cases = cases;
|
|
this.nothingThrownLabel = nothingThrownLabel;
|
|
}
|
|
Switch.prototype = {
|
|
trace: function (writer) {
|
|
if (this.nothingThrownLabel) {
|
|
writer.enter('if (label is ' + this.nothingThrownLabel + ') {');
|
|
}
|
|
this.determinant.trace(writer);
|
|
writer.writeLn('switch {');
|
|
for (var i = 0, j = this.cases.length; i < j; i++) {
|
|
this.cases[i].trace(writer);
|
|
}
|
|
writer.writeLn('}');
|
|
if (this.nothingThrownLabel) {
|
|
writer.leave('}');
|
|
}
|
|
}
|
|
};
|
|
function LabelCase(labels, body) {
|
|
this.kind = LABEL_CASE;
|
|
this.labels = labels;
|
|
this.body = body;
|
|
}
|
|
LabelCase.prototype = {
|
|
trace: function (writer) {
|
|
writer.enter('if (label is ' + this.labels.join(' or ') + ') {');
|
|
this.body && this.body.trace(writer);
|
|
writer.leave('}');
|
|
}
|
|
};
|
|
function LabelSwitch(cases) {
|
|
var labelMap = {};
|
|
for (var i = 0, j = cases.length; i < j; i++) {
|
|
var c = cases[i];
|
|
if (!c.labels) {
|
|
print(c.toSource());
|
|
}
|
|
for (var k = 0, l = c.labels.length; k < l; k++) {
|
|
labelMap[c.labels[k]] = c;
|
|
}
|
|
}
|
|
this.kind = LABEL_SWITCH;
|
|
this.cases = cases;
|
|
this.labelMap = labelMap;
|
|
}
|
|
LabelSwitch.prototype = {
|
|
trace: function (writer) {
|
|
for (var i = 0, j = this.cases.length; i < j; i++) {
|
|
this.cases[i].trace(writer);
|
|
}
|
|
}
|
|
};
|
|
function Exit(label) {
|
|
this.kind = EXIT;
|
|
this.label = label;
|
|
}
|
|
Exit.prototype = {
|
|
trace: function (writer) {
|
|
writer.writeLn('label = ' + this.label);
|
|
}
|
|
};
|
|
function Break(label, head) {
|
|
this.kind = BREAK;
|
|
this.label = label;
|
|
this.head = head;
|
|
}
|
|
Break.prototype = {
|
|
trace: function (writer) {
|
|
this.label && writer.writeLn('label = ' + this.label);
|
|
writer.writeLn('break');
|
|
}
|
|
};
|
|
function Continue(label, head) {
|
|
this.kind = CONTINUE;
|
|
this.label = label;
|
|
this.head = head;
|
|
this.necessary = true;
|
|
}
|
|
Continue.prototype = {
|
|
trace: function (writer) {
|
|
this.label && writer.writeLn('label = ' + this.label);
|
|
this.necessary && writer.writeLn('continue');
|
|
}
|
|
};
|
|
function Try(body, catches) {
|
|
this.kind = TRY;
|
|
this.body = body;
|
|
this.catches = catches;
|
|
}
|
|
Try.prototype = {
|
|
trace: function (writer) {
|
|
writer.enter('try {');
|
|
this.body.trace(writer);
|
|
writer.writeLn('label = ' + this.nothingThrownLabel);
|
|
for (var i = 0, j = this.catches.length; i < j; i++) {
|
|
this.catches[i].trace(writer);
|
|
}
|
|
writer.leave('}');
|
|
}
|
|
};
|
|
function Catch(varName, typeName, body) {
|
|
this.kind = CATCH;
|
|
this.varName = varName;
|
|
this.typeName = typeName;
|
|
this.body = body;
|
|
}
|
|
Catch.prototype = {
|
|
trace: function (writer) {
|
|
writer.outdent();
|
|
writer.enter('} catch (' + (this.varName || 'e') + (this.typeName ? ' : ' + this.typeName : '') + ') {');
|
|
this.body.trace(writer);
|
|
}
|
|
};
|
|
return {
|
|
SEQ: SEQ,
|
|
LOOP: LOOP,
|
|
IF: IF,
|
|
CASE: CASE,
|
|
SWITCH: SWITCH,
|
|
LABEL_CASE: LABEL_CASE,
|
|
LABEL_SWITCH: LABEL_SWITCH,
|
|
EXIT: EXIT,
|
|
BREAK: BREAK,
|
|
CONTINUE: CONTINUE,
|
|
TRY: TRY,
|
|
CATCH: CATCH,
|
|
Seq: Seq,
|
|
Loop: Loop,
|
|
If: If,
|
|
Case: Case,
|
|
Switch: Switch,
|
|
LabelCase: LabelCase,
|
|
LabelSwitch: LabelSwitch,
|
|
Exit: Exit,
|
|
Break: Break,
|
|
Continue: Continue,
|
|
Try: Try,
|
|
Catch: Catch
|
|
};
|
|
}();
|
|
var Analysis = function () {
|
|
function blockSetClass(length, blockById) {
|
|
var BlockSet = BitSetFunctor(length);
|
|
var ADDRESS_BITS_PER_WORD = BlockSet.ADDRESS_BITS_PER_WORD;
|
|
var BITS_PER_WORD = BlockSet.BITS_PER_WORD;
|
|
var BIT_INDEX_MASK = BlockSet.BIT_INDEX_MASK;
|
|
BlockSet.singleton = function singleton(b) {
|
|
var bs = new BlockSet();
|
|
bs.set(b.id);
|
|
bs.count = 1;
|
|
bs.dirty = 0;
|
|
return bs;
|
|
};
|
|
BlockSet.fromBlocks = function fromArray(other) {
|
|
var bs = new BlockSet();
|
|
bs.setBlocks(other);
|
|
return bs;
|
|
};
|
|
var Bsp = BlockSet.prototype;
|
|
if (BlockSet.singleword) {
|
|
Bsp.forEachBlock = function forEach(fn) {
|
|
true;
|
|
var byId = blockById;
|
|
var word = this.bits;
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
fn(byId[k]);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Bsp.choose = function choose() {
|
|
var byId = blockById;
|
|
var word = this.bits;
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
return byId[k];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Bsp.members = function members() {
|
|
var byId = blockById;
|
|
var set = [];
|
|
var word = this.bits;
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
set.push(byId[k]);
|
|
}
|
|
}
|
|
}
|
|
return set;
|
|
};
|
|
Bsp.setBlocks = function setBlocks(bs) {
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bs.length; i < j; i++) {
|
|
var id = bs[i].id;
|
|
bits |= 1 << (id & BIT_INDEX_MASK);
|
|
}
|
|
this.bits = bits;
|
|
};
|
|
} else {
|
|
Bsp.forEachBlock = function forEach(fn) {
|
|
true;
|
|
var byId = blockById;
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var word = bits[i];
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
fn(byId[i * BITS_PER_WORD + k]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Bsp.choose = function choose() {
|
|
var byId = blockById;
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var word = bits[i];
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
return byId[i * BITS_PER_WORD + k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Bsp.members = function members() {
|
|
var byId = blockById;
|
|
var set = [];
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bits.length; i < j; i++) {
|
|
var word = bits[i];
|
|
if (word) {
|
|
for (var k = 0; k < BITS_PER_WORD; k++) {
|
|
if (word & 1 << k) {
|
|
set.push(byId[i * BITS_PER_WORD + k]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return set;
|
|
};
|
|
Bsp.setBlocks = function setBlocks(bs) {
|
|
var bits = this.bits;
|
|
for (var i = 0, j = bs.length; i < j; i++) {
|
|
var id = bs[i].id;
|
|
bits[id >> ADDRESS_BITS_PER_WORD] |= 1 << (id & BIT_INDEX_MASK);
|
|
}
|
|
};
|
|
}
|
|
return BlockSet;
|
|
}
|
|
function Analysis(cfg, options) {
|
|
this.options = options || {};
|
|
this.BlockSet = blockSetClass(cfg.blocks.length, cfg.blocks);
|
|
this.hasExceptions = false;
|
|
this.normalizeReachableBlocks(cfg.root);
|
|
}
|
|
Analysis.prototype = {
|
|
normalizeReachableBlocks: function normalizeReachableBlocks(root) {
|
|
true;
|
|
var ONCE = 1;
|
|
var BUNCH_OF_TIMES = 2;
|
|
var BlockSet = this.BlockSet;
|
|
var blocks = [];
|
|
var visited = {};
|
|
var ancestors = {};
|
|
var worklist = [
|
|
root
|
|
];
|
|
var node;
|
|
ancestors[root.id] = true;
|
|
while (node = worklist.top()) {
|
|
if (visited[node.id]) {
|
|
if (visited[node.id] === ONCE) {
|
|
visited[node.id] = BUNCH_OF_TIMES;
|
|
blocks.push(node);
|
|
}
|
|
ancestors[node.id] = false;
|
|
worklist.pop();
|
|
continue;
|
|
}
|
|
visited[node.id] = ONCE;
|
|
ancestors[node.id] = true;
|
|
var successors = node.successors;
|
|
for (var i = 0, j = successors.length; i < j; i++) {
|
|
var s = successors[i];
|
|
if (ancestors[s.id]) {
|
|
if (!node.spbacks) {
|
|
node.spbacks = new BlockSet();
|
|
}
|
|
node.spbacks.set(s.id);
|
|
}
|
|
!visited[s.id] && worklist.push(s);
|
|
}
|
|
}
|
|
this.blocks = blocks.reverse();
|
|
},
|
|
computeDominance: function computeDominance() {
|
|
function intersectDominators(doms, b1, b2) {
|
|
var finger1 = b1;
|
|
var finger2 = b2;
|
|
while (finger1 !== finger2) {
|
|
while (finger1 > finger2) {
|
|
finger1 = doms[finger1];
|
|
}
|
|
while (finger2 > finger1) {
|
|
finger2 = doms[finger2];
|
|
}
|
|
}
|
|
return finger1;
|
|
}
|
|
var blocks = this.blocks;
|
|
var n = blocks.length;
|
|
var doms = new Array(n);
|
|
doms[0] = 0;
|
|
var rpo = [];
|
|
for (var b = 0; b < n; b++) {
|
|
rpo[blocks[b].id] = b;
|
|
blocks[b].dominatees = [];
|
|
}
|
|
var changed = true;
|
|
while (changed) {
|
|
changed = false;
|
|
for (var b = 1; b < n; b++) {
|
|
var predecessors = blocks[b].predecessors;
|
|
var j = predecessors.length;
|
|
var newIdom = rpo[predecessors[0].id];
|
|
if (!(newIdom in doms)) {
|
|
for (var i = 1; i < j; i++) {
|
|
newIdom = rpo[predecessors[i].id];
|
|
if (newIdom in doms) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
true;
|
|
for (var i = 0; i < j; i++) {
|
|
var p = rpo[predecessors[i].id];
|
|
if (p === newIdom) {
|
|
continue;
|
|
}
|
|
if (p in doms) {
|
|
newIdom = intersectDominators(doms, p, newIdom);
|
|
}
|
|
}
|
|
if (doms[b] !== newIdom) {
|
|
doms[b] = newIdom;
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
blocks[0].dominator = blocks[0];
|
|
var block;
|
|
for (var b = 1; b < n; b++) {
|
|
block = blocks[b];
|
|
var idom = blocks[doms[b]];
|
|
block.dominator = idom;
|
|
idom.dominatees.push(block);
|
|
block.npredecessors = block.predecessors.length;
|
|
}
|
|
var worklist = [
|
|
blocks[0]
|
|
];
|
|
blocks[0].level || (blocks[0].level = 0);
|
|
while (block = worklist.shift()) {
|
|
var dominatees = block.dominatees;
|
|
for (var i = 0, j = dominatees.length; i < j; i++) {
|
|
dominatees[i].level = block.level + 1;
|
|
}
|
|
worklist.push.apply(worklist, dominatees);
|
|
}
|
|
},
|
|
computeFrontiers: function computeFrontiers() {
|
|
var BlockSet = this.BlockSet;
|
|
var blocks = this.blocks;
|
|
for (var b = 0, n = blocks.length; b < n; b++) {
|
|
blocks[b].frontier = new BlockSet();
|
|
}
|
|
for (var b = 1, n = blocks.length; b < n; b++) {
|
|
var block = blocks[b];
|
|
var predecessors = block.predecessors;
|
|
if (predecessors.length >= 2) {
|
|
var idom = block.dominator;
|
|
for (var i = 0, j = predecessors.length; i < j; i++) {
|
|
var runner = predecessors[i];
|
|
while (runner !== idom) {
|
|
runner.frontier.set(block.id);
|
|
runner = runner.dominator;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
analyzeControlFlow: function analyzeControlFlow() {
|
|
this.computeDominance();
|
|
this.analyzedControlFlow = true;
|
|
return true;
|
|
},
|
|
markLoops: function markLoops() {
|
|
if (!this.analyzedControlFlow && !this.analyzeControlFlow()) {
|
|
return false;
|
|
}
|
|
var BlockSet = this.BlockSet;
|
|
function findSCCs(root) {
|
|
var preorderId = 1;
|
|
var preorder = {};
|
|
var assigned = {};
|
|
var unconnectedNodes = [];
|
|
var pendingNodes = [];
|
|
var sccs = [];
|
|
var level = root.level + 1;
|
|
var worklist = [
|
|
root
|
|
];
|
|
var node;
|
|
var u, s;
|
|
while (node = worklist.top()) {
|
|
if (preorder[node.id]) {
|
|
if (pendingNodes.peek() === node) {
|
|
pendingNodes.pop();
|
|
var scc = [];
|
|
do {
|
|
u = unconnectedNodes.pop();
|
|
assigned[u.id] = true;
|
|
scc.push(u);
|
|
} while (u !== node);
|
|
if (scc.length > 1 || u.spbacks && u.spbacks.get(u.id)) {
|
|
sccs.push(scc);
|
|
}
|
|
}
|
|
worklist.pop();
|
|
continue;
|
|
}
|
|
preorder[node.id] = preorderId++;
|
|
unconnectedNodes.push(node);
|
|
pendingNodes.push(node);
|
|
var successors = node.successors;
|
|
for (var i = 0, j = successors.length; i < j; i++) {
|
|
s = successors[i];
|
|
if (s.level < level) {
|
|
continue;
|
|
}
|
|
var sid = s.id;
|
|
if (!preorder[sid]) {
|
|
worklist.push(s);
|
|
} else if (!assigned[sid]) {
|
|
while (preorder[pendingNodes.peek().id] > preorder[sid]) {
|
|
pendingNodes.pop();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return sccs;
|
|
}
|
|
function findLoopHeads(blocks) {
|
|
var heads = new BlockSet();
|
|
for (var i = 0, j = blocks.length; i < j; i++) {
|
|
var block = blocks[i];
|
|
var spbacks = block.spbacks;
|
|
if (!spbacks) {
|
|
continue;
|
|
}
|
|
var successors = block.successors;
|
|
for (var k = 0, l = successors.length; k < l; k++) {
|
|
var s = successors[k];
|
|
if (spbacks.get(s.id)) {
|
|
heads.set(s.dominator.id);
|
|
}
|
|
}
|
|
}
|
|
return heads.members();
|
|
}
|
|
function LoopInfo(scc, loopId) {
|
|
var body = new BlockSet();
|
|
body.setBlocks(scc);
|
|
body.recount();
|
|
this.id = loopId;
|
|
this.body = body;
|
|
this.exit = new BlockSet();
|
|
this.save = {};
|
|
this.head = new BlockSet();
|
|
this.npredecessors = 0;
|
|
}
|
|
var heads = findLoopHeads(this.blocks);
|
|
if (heads.length <= 0) {
|
|
this.markedLoops = true;
|
|
return true;
|
|
}
|
|
var worklist = heads.sort(function (a, b) {
|
|
return a.level - b.level;
|
|
});
|
|
var loopId = 0;
|
|
for (var n = worklist.length - 1; n >= 0; n--) {
|
|
var top = worklist[n];
|
|
var sccs = findSCCs(top);
|
|
if (sccs.length === 0) {
|
|
continue;
|
|
}
|
|
for (var i = 0, j = sccs.length; i < j; i++) {
|
|
var scc = sccs[i];
|
|
var loop = new LoopInfo(scc, loopId++);
|
|
for (var k = 0, l = scc.length; k < l; k++) {
|
|
var h = scc[k];
|
|
if (h.level === top.level + 1 && !h.loop) {
|
|
h.loop = loop;
|
|
loop.head.set(h.id);
|
|
var predecessors = h.predecessors;
|
|
for (var pi = 0, pj = predecessors.length; pi < pj; pi++) {
|
|
loop.body.get(predecessors[pi].id) && h.npredecessors--;
|
|
}
|
|
loop.npredecessors += h.npredecessors;
|
|
}
|
|
}
|
|
for (var k = 0, l = scc.length; k < l; k++) {
|
|
var h = scc[k];
|
|
if (h.level === top.level + 1) {
|
|
h.npredecessors = loop.npredecessors;
|
|
}
|
|
}
|
|
loop.head.recount();
|
|
}
|
|
}
|
|
this.markedLoops = true;
|
|
return true;
|
|
},
|
|
induceControlTree: function induceControlTree() {
|
|
var hasExceptions = this.hasExceptions;
|
|
var BlockSet = this.BlockSet;
|
|
function maybe(exit, save) {
|
|
exit.recount();
|
|
if (exit.count === 0) {
|
|
return null;
|
|
}
|
|
exit.save = save;
|
|
return exit;
|
|
}
|
|
var exceptionId = this.blocks.length;
|
|
function induce(head, exit, save, loop, inLoopHead, lookupSwitch, fallthrough) {
|
|
var v = [];
|
|
while (head) {
|
|
if (head.count > 1) {
|
|
var exit2 = new BlockSet();
|
|
var save2 = {};
|
|
var cases = [];
|
|
var heads = head.members();
|
|
for (var i = 0, j = heads.length; i < j; i++) {
|
|
var h = heads[i];
|
|
var bid = h.id;
|
|
var c;
|
|
if (h.loop && head.contains(h.loop.head)) {
|
|
var loop2 = h.loop;
|
|
if (!loop2.induced) {
|
|
var lheads = loop2.head.members();
|
|
var lheadsave = 0;
|
|
for (k = 0, l = lheads.length; k < l; k++) {
|
|
lheadsave += head.save[lheads[k].id];
|
|
}
|
|
if (h.npredecessors - lheadsave > 0) {
|
|
h.npredecessors -= head.save[bid];
|
|
h.save = head.save[bid];
|
|
c = induce(h, exit2, save2, loop);
|
|
cases.push(new Control.LabelCase([
|
|
bid
|
|
], c));
|
|
} else {
|
|
for (k = 0, l = lheads.length; k < l; k++) {
|
|
var lh = lheads[k];
|
|
lh.npredecessors -= lheadsave;
|
|
lh.save = lheadsave;
|
|
}
|
|
c = induce(h, exit2, save2, loop);
|
|
cases.push(new Control.LabelCase(loop2.head.toArray(), c));
|
|
loop2.induced = true;
|
|
}
|
|
}
|
|
} else {
|
|
h.npredecessors -= head.save[bid];
|
|
h.save = head.save[bid];
|
|
c = induce(h, exit2, save2, loop);
|
|
cases.push(new Control.LabelCase([
|
|
bid
|
|
], c));
|
|
}
|
|
}
|
|
var pruned = [];
|
|
var k = 0;
|
|
var c;
|
|
for (var i = 0, j = cases.length; i < j; i++) {
|
|
c = cases[i];
|
|
var labels = c.labels;
|
|
var lk = 0;
|
|
for (var ln = 0, nlabels = labels.length; ln < nlabels; ln++) {
|
|
var bid = labels[ln];
|
|
if (exit2.get(bid) && heads[i].npredecessors - head.save[bid] > 0) {
|
|
pruned.push(bid);
|
|
} else {
|
|
labels[lk++] = bid;
|
|
}
|
|
}
|
|
labels.length = lk;
|
|
if (labels.length > 0) {
|
|
cases[k++] = c;
|
|
}
|
|
}
|
|
cases.length = k;
|
|
if (cases.length === 0) {
|
|
for (var i = 0, j = pruned.length; i < j; i++) {
|
|
var bid = pruned[i];
|
|
save[bid] = (save[bid] || 0) + head.save[bid];
|
|
exit.set(bid);
|
|
}
|
|
break;
|
|
}
|
|
v.push(new Control.LabelSwitch(cases));
|
|
head = maybe(exit2, save2);
|
|
continue;
|
|
}
|
|
var h, bid, c;
|
|
if (head.count === 1) {
|
|
h = head.choose();
|
|
bid = h.id;
|
|
h.npredecessors -= head.save[bid];
|
|
h.save = head.save[bid];
|
|
} else {
|
|
h = head;
|
|
bid = h.id;
|
|
}
|
|
if (inLoopHead) {
|
|
inLoopHead = false;
|
|
} else {
|
|
if (loop && !loop.body.get(bid)) {
|
|
h.npredecessors += h.save;
|
|
loop.exit.set(bid);
|
|
loop.save[bid] = (loop.save[bid] || 0) + h.save;
|
|
v.push(new Control.Break(bid, loop));
|
|
break;
|
|
}
|
|
if (loop && h.loop === loop) {
|
|
h.npredecessors += h.save;
|
|
v.push(new Control.Continue(bid, loop));
|
|
break;
|
|
}
|
|
if (h === fallthrough) {
|
|
break;
|
|
}
|
|
if (h.npredecessors > 0) {
|
|
h.npredecessors += h.save;
|
|
save[bid] = (save[bid] || 0) + h.save;
|
|
exit.set(bid);
|
|
v.push(lookupSwitch ? new Control.Break(bid, lookupSwitch) : new Control.Exit(bid));
|
|
break;
|
|
}
|
|
if (h.loop) {
|
|
var l = h.loop;
|
|
var body;
|
|
if (l.head.count === 1) {
|
|
body = induce(l.head.choose(), null, null, l, true);
|
|
} else {
|
|
var lcases = [];
|
|
var lheads = l.head.members();
|
|
for (var i = 0, j = lheads.length; i < j; i++) {
|
|
var lh = lheads[i];
|
|
var lbid = lh.id;
|
|
var c = induce(lh, null, null, l, true);
|
|
lcases.push(new Control.LabelCase([
|
|
lbid
|
|
], c));
|
|
}
|
|
body = new Control.LabelSwitch(lcases);
|
|
}
|
|
v.push(new Control.Loop(body));
|
|
head = maybe(l.exit, l.save);
|
|
continue;
|
|
}
|
|
}
|
|
var sv;
|
|
var successors;
|
|
var exit2 = new BlockSet();
|
|
var save2 = {};
|
|
if (hasExceptions && h.hasCatches) {
|
|
var allsuccessors = h.successors;
|
|
var catchsuccessors = [];
|
|
successors = [];
|
|
for (var i = 0, j = allsuccessors.length; i < j; i++) {
|
|
var s = allsuccessors[i];
|
|
(s.exception ? catchsuccessors : successors).push(s);
|
|
}
|
|
var catches = [];
|
|
for (var i = 0, j = catchsuccessors.length; i < j; i++) {
|
|
var t = catchsuccessors[i];
|
|
t.npredecessors -= 1;
|
|
t.save = 1;
|
|
var c = induce(t, exit2, save2, loop);
|
|
var ex = t.exception;
|
|
catches.push(new Control.Catch(ex.varName, ex.typeName, c));
|
|
}
|
|
sv = new Control.Try(h, catches);
|
|
} else {
|
|
successors = h.successors;
|
|
sv = h;
|
|
}
|
|
if (successors.length > 2) {
|
|
var cases = [];
|
|
var targets = successors;
|
|
for (var i = targets.length - 1; i >= 0; i--) {
|
|
var t = targets[i];
|
|
t.npredecessors -= 1;
|
|
t.save = 1;
|
|
c = induce(t, exit2, save2, loop, null, h, targets[i + 1]);
|
|
cases.unshift(new Control.Case(i, c));
|
|
}
|
|
cases.top().index = undefined;
|
|
if (hasExceptions && h.hasCatches) {
|
|
sv.nothingThrownLabel = exceptionId;
|
|
sv = new Control.Switch(sv, cases, exceptionId++);
|
|
} else {
|
|
sv = new Control.Switch(sv, cases);
|
|
}
|
|
head = maybe(exit2, save2);
|
|
} else if (successors.length === 2) {
|
|
var branch1 = h.hasFlippedSuccessors ? successors[1] : successors[0];
|
|
var branch2 = h.hasFlippedSuccessors ? successors[0] : successors[1];
|
|
branch1.npredecessors -= 1;
|
|
branch1.save = 1;
|
|
var c1 = induce(branch1, exit2, save2, loop);
|
|
branch2.npredecessors -= 1;
|
|
branch2.save = 1;
|
|
var c2 = induce(branch2, exit2, save2, loop);
|
|
if (hasExceptions && h.hasCatches) {
|
|
sv.nothingThrownLabel = exceptionId;
|
|
sv = new Control.If(sv, c1, c2, exceptionId++);
|
|
} else {
|
|
sv = new Control.If(sv, c1, c2);
|
|
}
|
|
head = maybe(exit2, save2);
|
|
} else {
|
|
c = successors[0];
|
|
if (c) {
|
|
if (hasExceptions && h.hasCatches) {
|
|
sv.nothingThrownLabel = c.id;
|
|
save2[c.id] = (save2[c.id] || 0) + 1;
|
|
exit2.set(c.id);
|
|
head = maybe(exit2, save2);
|
|
} else {
|
|
c.npredecessors -= 1;
|
|
c.save = 1;
|
|
head = c;
|
|
}
|
|
} else {
|
|
if (hasExceptions && h.hasCatches) {
|
|
sv.nothingThrownLabel = -1;
|
|
head = maybe(exit2, save2);
|
|
} else {
|
|
head = c;
|
|
}
|
|
}
|
|
}
|
|
v.push(sv);
|
|
}
|
|
if (v.length > 1) {
|
|
return new Control.Seq(v);
|
|
}
|
|
return v[0];
|
|
}
|
|
var root = this.blocks[0];
|
|
this.controlTree = induce(root, new BlockSet(), {});
|
|
},
|
|
restructureControlFlow: function restructureControlFlow() {
|
|
Timer.start('Restructure Control Flow');
|
|
if (!this.markedLoops && !this.markLoops()) {
|
|
Timer.stop();
|
|
return false;
|
|
}
|
|
this.induceControlTree();
|
|
this.restructuredControlFlow = true;
|
|
Timer.stop();
|
|
return true;
|
|
},
|
|
trace: function (writer) {
|
|
function bid(node) {
|
|
return node.id;
|
|
}
|
|
function traceBlock(block) {
|
|
if (!block.dominator) {
|
|
writer.enter('block unreachable {');
|
|
} else {
|
|
writer.enter('block ' + block.id + (block.successors.length > 0 ? ' -> ' + block.successors.map(bid).join(',') : '') + ' {');
|
|
writer.writeLn('npredecessors'.padRight(' ', 10) + block.npredecessors);
|
|
writer.writeLn('idom'.padRight(' ', 10) + block.dominator.id);
|
|
writer.writeLn('domcs'.padRight(' ', 10) + block.dominatees.map(bid).join(','));
|
|
if (block.frontier) {
|
|
writer.writeLn('frontier'.padRight(' ', 10) + '{' + block.frontier.toArray().join(',') + '}');
|
|
}
|
|
writer.writeLn('level'.padRight(' ', 10) + block.level);
|
|
}
|
|
if (block.loop) {
|
|
writer.writeLn('loop'.padRight(' ', 10) + '{' + block.loop.body.toArray().join(',') + '}');
|
|
writer.writeLn(' id'.padRight(' ', 10) + block.loop.id);
|
|
writer.writeLn(' head'.padRight(' ', 10) + '{' + block.loop.head.toArray().join(',') + '}');
|
|
writer.writeLn(' exit'.padRight(' ', 10) + '{' + block.loop.exit.toArray().join(',') + '}');
|
|
writer.writeLn(' npredecessors'.padRight(' ', 10) + block.loop.npredecessors);
|
|
}
|
|
writer.writeLn('');
|
|
if (block.position >= 0) {
|
|
for (var bci = block.position; bci <= block.end.position; bci++) {
|
|
writer.writeLn(('' + bci).padRight(' ', 5) + bytecodes[bci]);
|
|
}
|
|
} else {
|
|
writer.writeLn('abstract');
|
|
}
|
|
writer.leave('}');
|
|
}
|
|
var bytecodes = this.bytecodes;
|
|
writer.enter('analysis {');
|
|
writer.enter('cfg {');
|
|
this.blocks.forEach(traceBlock);
|
|
writer.leave('}');
|
|
if (this.controlTree) {
|
|
writer.enter('control-tree {');
|
|
this.controlTree.trace(writer);
|
|
writer.leave('}');
|
|
}
|
|
writer.leave('}');
|
|
},
|
|
traceCFG: makeVizTrace([
|
|
{
|
|
fn: function (n) {
|
|
return n.successors || [];
|
|
},
|
|
style: ''
|
|
}
|
|
], [
|
|
{
|
|
fn: function (n) {
|
|
return n.predecessors || [];
|
|
},
|
|
style: ''
|
|
}
|
|
]),
|
|
traceDJ: makeVizTrace([
|
|
{
|
|
fn: function (n) {
|
|
return n.dominatees || [];
|
|
},
|
|
style: 'style=dashed'
|
|
},
|
|
{
|
|
fn: function (n) {
|
|
var crosses = new this.BlockSet();
|
|
crosses.setBlocks(n.successors);
|
|
crosses.subtract(this.BlockSet.fromBlocks(n.dominatees));
|
|
n.spbacks && crosses.subtract(n.spbacks);
|
|
return crosses.members();
|
|
},
|
|
style: ''
|
|
},
|
|
{
|
|
fn: function (n) {
|
|
return n.spbacks ? n.spbacks.members() : [];
|
|
},
|
|
style: 'style=bold'
|
|
}
|
|
], [
|
|
{
|
|
fn: function (n) {
|
|
return n.predecessors || [];
|
|
},
|
|
style: ''
|
|
}
|
|
], function (idFn, writer) {
|
|
var root = this.bytecodes[0];
|
|
var worklist = [
|
|
root
|
|
];
|
|
var n;
|
|
var level = root.level;
|
|
var currentLevel = [];
|
|
while (n = worklist.shift()) {
|
|
if (level != n.level) {
|
|
writer.writeLn('{rank=same; ' + currentLevel.map(function (n) {
|
|
return 'block_' + idFn(n);
|
|
}).join(' ') + '}');
|
|
currentLevel.length = 0;
|
|
level = n.level;
|
|
}
|
|
currentLevel.push(n);
|
|
worklist.push.apply(worklist, n.dominatees);
|
|
}
|
|
})
|
|
};
|
|
function makeVizTrace(successorFns, predecessorFns, postHook) {
|
|
return function (writer, name, prefix) {
|
|
function idFn(n) {
|
|
return prefix + n.id;
|
|
}
|
|
var analysis = this;
|
|
function bindToThis(x) {
|
|
x.fn = x.fn.bind(analysis);
|
|
}
|
|
prefix = prefix || '';
|
|
var bytecodes = this.bytecodes;
|
|
if (!bytecodes) {
|
|
return;
|
|
}
|
|
successorFns.forEach(bindToThis);
|
|
predecessorFns.forEach(bindToThis);
|
|
writeGraphViz(writer, name.toString(), bytecodes[0], idFn, function (n) {
|
|
return n.successors || [];
|
|
}, successorFns, predecessorFns, function (n) {
|
|
var str = 'Block: ' + n.id + '\\l';
|
|
return str;
|
|
}, postHook && postHook.bind(this, idFn));
|
|
};
|
|
}
|
|
return Analysis;
|
|
}();
|
|
exports.Control = Control;
|
|
exports.analyze = function (cfg) {
|
|
var analysis = new Analysis(cfg);
|
|
analysis.restructureControlFlow();
|
|
return analysis.controlTree;
|
|
};
|
|
}(typeof exports === 'undefined' ? Looper = {} : exports));
|
|
(function (exports) {
|
|
var TRACE_REGISTER_ALLOCATOR = false;
|
|
var T = estransform;
|
|
var Node = T.Node;
|
|
var Identifier = T.Identifier;
|
|
var VariableDeclaration = T.VariableDeclaration;
|
|
var VariableDeclarator = T.VariableDeclarator;
|
|
var AssignmentExpression = T.AssignmentExpression;
|
|
var MemberExpression = T.MemberExpression;
|
|
var IfStatement = T.IfStatement;
|
|
var WhileStatement = T.WhileStatement;
|
|
var FunctionDeclaration = T.FunctionDeclaration;
|
|
var writer = new IndentingWriter();
|
|
var LinearScan = function () {
|
|
function Interval(id, start, end) {
|
|
this.id = id;
|
|
this.start = start;
|
|
this.end = end;
|
|
}
|
|
Interval.prototype.toString = function () {
|
|
return '[' + this.start + ',' + this.end + ']';
|
|
};
|
|
function linearScan(intervals, maxRegisters) {
|
|
this.intervals = intervals.slice(0);
|
|
this.maxRegisters = maxRegisters;
|
|
}
|
|
linearScan.prototype.allocate = function () {
|
|
var intervals = this.intervals;
|
|
this.intervals.sort(function (a, b) {
|
|
return a.start - b.start;
|
|
});
|
|
var active = new SortedList(function (a, b) {
|
|
return a.end - b.end;
|
|
});
|
|
var maxRegisters = this.maxRegisters;
|
|
var freeRegisters = [];
|
|
for (var i = maxRegisters - 1; i >= 0; i--) {
|
|
freeRegisters.push('R' + i);
|
|
}
|
|
intervals.forEach(function (i) {
|
|
expireOldIntervals(i);
|
|
if (active.length === maxRegisters) {
|
|
notImplemented('Cannot Spill');
|
|
} else {
|
|
i.register = freeRegisters.pop();
|
|
TRACE_REGISTER_ALLOCATOR && writer.writeLn('Allocate: ' + i + ' ' + i.id + ' -> ' + i.register);
|
|
active.push(i);
|
|
}
|
|
});
|
|
function expireOldIntervals(i) {
|
|
active.forEach(function (j) {
|
|
if (j.end >= i.start) {
|
|
return SortedList.RETURN;
|
|
}
|
|
freeRegisters.push(j.register);
|
|
TRACE_REGISTER_ALLOCATOR && writer.writeLn('Release: ' + j + ' -> ' + j.register);
|
|
return SortedList.DELETE;
|
|
});
|
|
}
|
|
};
|
|
linearScan.Interval = Interval;
|
|
return linearScan;
|
|
}();
|
|
function allocateRegisters(program) {
|
|
var scan = T.makePass('scan', 'scanNode');
|
|
var label = 0;
|
|
Node.prototype.scan = function (o) {
|
|
this.position = label++;
|
|
return scan.apply(this, o);
|
|
};
|
|
var variables = [];
|
|
var variableIndexMap = {};
|
|
var identifiers = [];
|
|
FunctionDeclaration.prototype.scan = function () {
|
|
this.params.forEach(function (identifier) {
|
|
if (!(identifier.name in variableIndexMap)) {
|
|
variableIndexMap[identifier.name] = variables.length;
|
|
variables.push(identifier.name);
|
|
}
|
|
});
|
|
this.body.scan();
|
|
return this;
|
|
};
|
|
VariableDeclarator.prototype.scan = function () {
|
|
this.position = label++;
|
|
if (!(this.id.name in variableIndexMap)) {
|
|
variableIndexMap[this.id.name] = variables.length;
|
|
variables.push(this.id.name);
|
|
}
|
|
return this;
|
|
};
|
|
AssignmentExpression.prototype.scan = function (o) {
|
|
this.left.scan(o);
|
|
this.right.scan(o);
|
|
this.position = label++;
|
|
return this;
|
|
};
|
|
WhileStatement.prototype.scan = function (o) {
|
|
this.position = label++;
|
|
this.test.scan(o);
|
|
this.body.scan(o);
|
|
this.afterPosition = label++;
|
|
return this;
|
|
};
|
|
program.scan();
|
|
TRACE_REGISTER_ALLOCATOR && writer.writeLn('Local Variables: ' + variables);
|
|
var Set = BitSetFunctor(variables.length);
|
|
var Range = BitSetFunctor(label);
|
|
var ranges = [];
|
|
for (var i = 0; i < variables.length; i++) {
|
|
ranges.push(new Range());
|
|
}
|
|
function fill(range) {
|
|
var start = -1;
|
|
for (var i = 0; i < range.length; i++) {
|
|
if (range.get(i)) {
|
|
start = i;
|
|
break;
|
|
}
|
|
}
|
|
for (var i = range.length - 1; i >= 0; i--) {
|
|
if (range.get(i)) {
|
|
end = i;
|
|
break;
|
|
}
|
|
}
|
|
for (var i = start; i < end; i++) {
|
|
range.set(i);
|
|
}
|
|
}
|
|
function getRange(range) {
|
|
var start = -1, end = -1;
|
|
for (var i = 0; i < range.length; i++) {
|
|
if (range.get(i)) {
|
|
start = i;
|
|
break;
|
|
}
|
|
}
|
|
for (var i = range.length - 1; i >= 0; i--) {
|
|
if (range.get(i)) {
|
|
end = i;
|
|
break;
|
|
}
|
|
}
|
|
return [
|
|
start,
|
|
end
|
|
];
|
|
}
|
|
function use(set, name, position) {
|
|
var index = variableIndexMap[name];
|
|
ranges[index].set(position);
|
|
set.set(index);
|
|
}
|
|
function def(set, name, position) {
|
|
var index = variableIndexMap[name];
|
|
ranges[index].set(position);
|
|
set.clear(index);
|
|
}
|
|
Node.prototype.markLiveness = T.makePass('markLiveness', 'markLivenessNode', true);
|
|
Identifier.prototype.markLiveness = function (o) {
|
|
var name = this.name;
|
|
if (name === 'undefined') {
|
|
return this;
|
|
}
|
|
if (o && o.isProperty) {
|
|
return this;
|
|
}
|
|
if (!(name in variableIndexMap)) {
|
|
return this;
|
|
}
|
|
identifiers.push(this);
|
|
var live = o.live;
|
|
use(live, name, this.position);
|
|
return this;
|
|
};
|
|
VariableDeclarator.prototype.markLiveness = function (o) {
|
|
var live = o.live;
|
|
identifiers.push(this.id);
|
|
return this;
|
|
};
|
|
IfStatement.prototype.markLiveness = function (o) {
|
|
var a = o.live.clone();
|
|
var b = o.live.clone();
|
|
this.alternate && this.alternate.markLiveness({
|
|
live: a
|
|
});
|
|
this.consequent && this.consequent.markLiveness({
|
|
live: b
|
|
});
|
|
o.live.assign(a);
|
|
o.live._union(b);
|
|
this.test.markLiveness(o);
|
|
return this;
|
|
};
|
|
WhileStatement.prototype.markLiveness = function (o) {
|
|
var a = o.live.clone();
|
|
TRACE_REGISTER_ALLOCATOR && writer.writeLn('END OF LOOP: ' + a);
|
|
var afterPosition = this.afterPosition;
|
|
do {
|
|
var b = a.clone();
|
|
this.body.markLiveness({
|
|
live: a
|
|
});
|
|
this.test.markLiveness({
|
|
live: a
|
|
});
|
|
TRACE_REGISTER_ALLOCATOR && writer.writeLn('TOP OF LOOP: ' + a);
|
|
var iterate = !b.equals(a);
|
|
if (iterate) {
|
|
TRACE_REGISTER_ALLOCATOR && writer.writeLn('ITERATE');
|
|
a.forEach(function (i) {
|
|
ranges[i].set(afterPosition);
|
|
});
|
|
}
|
|
} while (iterate);
|
|
o.live.assign(a);
|
|
return this;
|
|
};
|
|
AssignmentExpression.prototype.markLiveness = function (o) {
|
|
this.right.markLiveness(o);
|
|
if (this.left instanceof Identifier) {
|
|
def(o.live, this.left.name, this.position);
|
|
identifiers.push(this.left);
|
|
} else {
|
|
this.left.markLiveness(o);
|
|
}
|
|
return this;
|
|
};
|
|
MemberExpression.prototype.markLiveness = function (o) {
|
|
if (this.computed || !(this.property instanceof Identifier)) {
|
|
this.property.markLiveness(o);
|
|
}
|
|
this.object.markLiveness(o);
|
|
return this;
|
|
};
|
|
program.markLiveness({
|
|
live: new Set()
|
|
});
|
|
var intervals = [];
|
|
for (var i = 0; i < ranges.length; i++) {
|
|
var r = getRange(ranges[i]);
|
|
intervals.push(new LinearScan.Interval(i, r[0], r[1]));
|
|
}
|
|
var allocator = new LinearScan(intervals, 1024);
|
|
allocator.allocate();
|
|
var map = createEmptyObject();
|
|
for (var i = 0; i < variables.length; i++) {
|
|
map[variables[i]] = intervals[i].register;
|
|
}
|
|
if (true) {
|
|
for (var i = 0; i < identifiers.length; i++) {
|
|
if (identifiers[i].patched) {
|
|
continue;
|
|
}
|
|
identifiers[i].name = map[identifiers[i].name];
|
|
identifiers[i].patched = true;
|
|
}
|
|
}
|
|
if (TRACE_REGISTER_ALLOCATOR) {
|
|
for (var i = 0; i < ranges.length; i++) {
|
|
fill(ranges[i]);
|
|
writer.writeLn(String(i).padLeft(' ', 3) + ' ' + variables[i].padRight(' ', 5) + ': ' + ranges[i].toBitString('=', ' ') + ' ' + intervals[i].register);
|
|
}
|
|
}
|
|
return program;
|
|
}
|
|
Transform.transform = function (program) {
|
|
allocateRegisters(program);
|
|
};
|
|
}(typeof exports === 'undefined' ? Transform = {} : exports));
|
|
(function (exports) {
|
|
var T = estransform;
|
|
var Literal = T.Literal;
|
|
var Identifier = T.Identifier;
|
|
var VariableDeclaration = T.VariableDeclaration;
|
|
var VariableDeclarator = T.VariableDeclarator;
|
|
var MemberExpression = T.MemberExpression;
|
|
var BinaryExpression = T.BinaryExpression;
|
|
var CallExpression = T.CallExpression;
|
|
var AssignmentExpression = T.AssignmentExpression;
|
|
var ExpressionStatement = T.ExpressionStatement;
|
|
var ReturnStatement = T.ReturnStatement;
|
|
var FunctionDeclaration = T.FunctionDeclaration;
|
|
var ConditionalExpression = T.ConditionalExpression;
|
|
var ObjectExpression = T.ObjectExpression;
|
|
var ArrayExpression = T.ArrayExpression;
|
|
var UnaryExpression = T.UnaryExpression;
|
|
var NewExpression = T.NewExpression;
|
|
var Property = T.Property;
|
|
var BlockStatement = T.BlockStatement;
|
|
var ThisExpression = T.ThisExpression;
|
|
var ThrowStatement = T.ThrowStatement;
|
|
var IfStatement = T.IfStatement;
|
|
var WhileStatement = T.WhileStatement;
|
|
var BreakStatement = T.BreakStatement;
|
|
var ContinueStatement = T.ContinueStatement;
|
|
var SwitchStatement = T.SwitchStatement;
|
|
var SwitchCase = T.SwitchCase;
|
|
var Block = IR.Block;
|
|
var Operator = IR.Operator;
|
|
var Projection = IR.Projection;
|
|
var Start = IR.Start;
|
|
var Control = Looper.Control;
|
|
var Variable = IR.Variable;
|
|
Control.Break.prototype.compile = function (cx, state) {
|
|
return cx.compileBreak(this, state);
|
|
};
|
|
Control.Continue.prototype.compile = function (cx, state) {
|
|
return cx.compileContinue(this, state);
|
|
};
|
|
Control.Exit.prototype.compile = function (cx, state) {
|
|
return cx.compileExit(this, state);
|
|
};
|
|
Control.LabelSwitch.prototype.compile = function (cx, state) {
|
|
return cx.compileLabelSwitch(this, state);
|
|
};
|
|
Control.Seq.prototype.compile = function (cx, state) {
|
|
return cx.compileSequence(this, state);
|
|
};
|
|
Block.prototype.compile = function (cx, state) {
|
|
return cx.compileBlock(this, state);
|
|
};
|
|
Control.Loop.prototype.compile = function (cx, state) {
|
|
return cx.compileLoop(this, state);
|
|
};
|
|
Control.Switch.prototype.compile = function (cx, state) {
|
|
return cx.compileSwitch(this, state);
|
|
};
|
|
Control.If.prototype.compile = function (cx, state) {
|
|
return cx.compileIf(this, state);
|
|
};
|
|
Control.Try.prototype.compile = function (cx, state) {
|
|
return cx.compileTry(this, state);
|
|
};
|
|
function constant(value) {
|
|
if (typeof value === 'string' || value === null || value === true || value === false) {
|
|
return new Literal(value);
|
|
} else if (value === undefined) {
|
|
return new Identifier('undefined');
|
|
} else if (typeof value === 'object' || typeof value === 'function') {
|
|
return new Identifier(objectConstantName(value));
|
|
} else if (typeof value === 'number' && isNaN(value)) {
|
|
return new Identifier('NaN');
|
|
} else if (value === Infinity) {
|
|
return new Identifier('Infinity');
|
|
} else if (value === -Infinity) {
|
|
return new UnaryExpression('-', new Identifier('Infinity'));
|
|
} else if (typeof value === 'number' && 1 / value < 0) {
|
|
return new UnaryExpression('-', new Literal(Math.abs(value)));
|
|
} else if (typeof value === 'number') {
|
|
return new Literal(value);
|
|
} else {
|
|
unexpected('Cannot emit constant for value: ', value);
|
|
}
|
|
}
|
|
function id(name) {
|
|
true;
|
|
return new Identifier(name);
|
|
}
|
|
function isIdentifierStart(c) {
|
|
return c === '$' || c === '_' || c === '\\' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
|
|
}
|
|
function isIdentifierPart(c) {
|
|
return c === '$' || c === '_' || c === '\\' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9';
|
|
}
|
|
function isIdentifierName(s) {
|
|
if (!isIdentifierStart(s[0])) {
|
|
return false;
|
|
}
|
|
for (var i = 1; i < s.length; i++) {
|
|
if (!isIdentifierPart(s[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function property(obj) {
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
var x = arguments[i];
|
|
if (typeof x === 'string') {
|
|
if (isIdentifierName(x)) {
|
|
obj = new MemberExpression(obj, new Identifier(x), false);
|
|
} else {
|
|
obj = new MemberExpression(obj, new Literal(x), true);
|
|
}
|
|
} else if (x instanceof Literal && isIdentifierName(x.value)) {
|
|
obj = new MemberExpression(obj, new Identifier(x.value), false);
|
|
} else {
|
|
obj = new MemberExpression(obj, x, true);
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
function call(callee, args) {
|
|
true;
|
|
true;
|
|
return new CallExpression(callee, args);
|
|
}
|
|
function callCall(callee, object, args) {
|
|
return call(property(callee, 'call'), [
|
|
object
|
|
].concat(args));
|
|
}
|
|
function assignment(left, right) {
|
|
true;
|
|
return new AssignmentExpression(left, '=', right);
|
|
}
|
|
function variableDeclaration(declarations) {
|
|
return new VariableDeclaration('var', declarations);
|
|
}
|
|
function negate(node) {
|
|
if (node instanceof Constant) {
|
|
if (node.value === true || node.value === false) {
|
|
return constant(!node.value);
|
|
}
|
|
} else if (node instanceof Identifier) {
|
|
return new UnaryExpression(Operator.FALSE.name, node);
|
|
}
|
|
true;
|
|
var left = node instanceof BinaryExpression ? node.left : node.argument;
|
|
var right = node.right;
|
|
var operator = Operator.fromName(node.operator);
|
|
if (operator === Operator.EQ && right instanceof Literal && right.value === false) {
|
|
return left;
|
|
}
|
|
if (operator === Operator.FALSE) {
|
|
return left;
|
|
}
|
|
if (operator.not) {
|
|
if (node instanceof BinaryExpression) {
|
|
return new BinaryExpression(operator.not.name, left, right);
|
|
} else {
|
|
return new UnaryExpression(operator.not.name, left);
|
|
}
|
|
}
|
|
return new UnaryExpression(Operator.FALSE.name, node);
|
|
}
|
|
function Context() {
|
|
this.label = new Variable('$L');
|
|
this.variables = [];
|
|
this.parameters = [];
|
|
}
|
|
Context.prototype.useVariable = function (variable) {
|
|
true;
|
|
return this.variables.pushUnique(variable);
|
|
};
|
|
Context.prototype.useParameter = function (parameter) {
|
|
return this.parameters[parameter.index] = parameter;
|
|
};
|
|
Context.prototype.compileLabelBody = function compileLabelBody(node) {
|
|
var body = [];
|
|
if (node.label !== undefined) {
|
|
this.useVariable(this.label);
|
|
body.push(new ExpressionStatement(assignment(id(this.label.name), new Literal(node.label))));
|
|
}
|
|
return body;
|
|
};
|
|
Context.prototype.compileBreak = function compileBreak(node) {
|
|
var body = this.compileLabelBody(node);
|
|
body.push(new BreakStatement(null));
|
|
return new BlockStatement(body);
|
|
};
|
|
Context.prototype.compileContinue = function compileContinue(node) {
|
|
var body = this.compileLabelBody(node);
|
|
body.push(new ContinueStatement(null));
|
|
return new BlockStatement(body);
|
|
};
|
|
Context.prototype.compileExit = function compileExit(node) {
|
|
return new BlockStatement(this.compileLabelBody(node));
|
|
};
|
|
Context.prototype.compileIf = function compileIf(node) {
|
|
var cr = node.cond.compile(this);
|
|
var tr = null, er = null;
|
|
if (node.then) {
|
|
tr = node.then.compile(this);
|
|
}
|
|
if (node.else) {
|
|
er = node.else.compile(this);
|
|
}
|
|
var condition = compileValue(cr.end.predicate, this);
|
|
condition = node.negated ? negate(condition) : condition;
|
|
cr.body.push(new IfStatement(condition, tr || new BlockStatement([]), er || null));
|
|
return cr;
|
|
};
|
|
Context.prototype.compileSwitch = function compileSwitch(node) {
|
|
var dr = node.determinant.compile(this);
|
|
var cases = [];
|
|
node.cases.forEach(function (x) {
|
|
var br;
|
|
if (x.body) {
|
|
br = x.body.compile(this);
|
|
}
|
|
var test = typeof x.index === 'number' ? new Literal(x.index) : undefined;
|
|
cases.push(new SwitchCase(test, br ? [
|
|
br
|
|
] : []));
|
|
}, this);
|
|
var determinant = compileValue(dr.end.determinant, this);
|
|
dr.body.push(new SwitchStatement(determinant, cases, false));
|
|
return dr;
|
|
};
|
|
Context.prototype.compileLabelSwitch = function compileLabelSwitch(node) {
|
|
var statement = null;
|
|
var labelName = id(this.label.name);
|
|
function compileLabelTest(labelID) {
|
|
true;
|
|
return new BinaryExpression('===', labelName, new Literal(labelID));
|
|
}
|
|
for (var i = node.cases.length - 1; i >= 0; i--) {
|
|
var c = node.cases[i];
|
|
var labels = c.labels;
|
|
var labelTest = compileLabelTest(labels[0]);
|
|
for (var j = 1; j < labels.length; j++) {
|
|
labelTest = new BinaryExpression('||', labelTest, compileLabelTest(labels[j]));
|
|
}
|
|
statement = new IfStatement(labelTest, c.body ? c.body.compile(this) : new BlockStatement(), statement);
|
|
}
|
|
return statement;
|
|
};
|
|
Context.prototype.compileLoop = function compileLoop(node) {
|
|
var br = node.body.compile(this);
|
|
return new WhileStatement(constant(true), br);
|
|
};
|
|
Context.prototype.compileSequence = function compileSequence(node) {
|
|
var cx = this;
|
|
var body = [];
|
|
node.body.forEach(function (x) {
|
|
var result = x.compile(cx);
|
|
if (result instanceof BlockStatement) {
|
|
body = body.concat(result.body);
|
|
} else {
|
|
body.push(result);
|
|
}
|
|
});
|
|
return new BlockStatement(body);
|
|
};
|
|
Context.prototype.compileBlock = function compileBlock(block) {
|
|
var body = [];
|
|
for (var i = 1; i < block.nodes.length - 1; i++) {
|
|
var node = block.nodes[i];
|
|
var statement;
|
|
var to;
|
|
var from;
|
|
if (node instanceof IR.Throw) {
|
|
statement = compileValue(node, this, true);
|
|
} else {
|
|
if (node instanceof IR.Move) {
|
|
to = id(node.to.name);
|
|
this.useVariable(node.to);
|
|
from = compileValue(node.from, this);
|
|
} else {
|
|
if (node.variable) {
|
|
to = id(node.variable.name);
|
|
this.useVariable(node.variable);
|
|
} else {
|
|
to = null;
|
|
}
|
|
from = compileValue(node, this, true);
|
|
}
|
|
if (to) {
|
|
statement = new ExpressionStatement(assignment(to, from));
|
|
} else {
|
|
statement = new ExpressionStatement(from);
|
|
}
|
|
}
|
|
body.push(statement);
|
|
}
|
|
var end = block.nodes.last();
|
|
if (end instanceof IR.Stop) {
|
|
body.push(new ReturnStatement(compileValue(end.argument, this)));
|
|
}
|
|
var result = new BlockStatement(body);
|
|
result.end = block.nodes.last();
|
|
true;
|
|
return result;
|
|
};
|
|
function compileValue(value, cx, noVariable) {
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
if (noVariable || !value.variable) {
|
|
var node = value.compile(cx);
|
|
return node;
|
|
}
|
|
true;
|
|
return id(value.variable.name);
|
|
}
|
|
function compileMultiname(name, cx) {
|
|
return [
|
|
compileValue(name.namespaces, cx),
|
|
compileValue(name.name, cx),
|
|
constant(name.flags)
|
|
];
|
|
}
|
|
function isArray(array) {
|
|
return array instanceof Array;
|
|
}
|
|
function compileValues(values, cx) {
|
|
true;
|
|
return values.map(function (value) {
|
|
return compileValue(value, cx);
|
|
});
|
|
}
|
|
IR.Parameter.prototype.compile = function (cx) {
|
|
cx.useParameter(this);
|
|
return id(this.name);
|
|
};
|
|
IR.Constant.prototype.compile = function (cx) {
|
|
return constant(this.value);
|
|
};
|
|
IR.Variable.prototype.compile = function (cx) {
|
|
return id(this.name);
|
|
};
|
|
IR.Phi.prototype.compile = function (cx) {
|
|
true;
|
|
return compileValue(this.variable, cx);
|
|
};
|
|
IR.ASScope.prototype.compile = function (cx) {
|
|
var parent = compileValue(this.parent, cx);
|
|
var object = compileValue(this.object, cx);
|
|
var isWith = new Literal(this.isWith);
|
|
return new NewExpression(id('Scope'), [
|
|
parent,
|
|
object,
|
|
isWith
|
|
]);
|
|
};
|
|
IR.ASFindProperty.prototype.compile = function (cx) {
|
|
var scope = compileValue(this.scope, cx);
|
|
var name = compileMultiname(this.name, cx);
|
|
var domain = compileValue(this.domain, cx);
|
|
var strict = new Literal(this.strict);
|
|
return call(property(scope, 'findScopeProperty'), name.concat([
|
|
domain,
|
|
strict
|
|
]));
|
|
};
|
|
IR.ASGetProperty.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
if (this.flags & IR.Flags.INDEXED) {
|
|
true;
|
|
return call(property(object, 'asGetNumericProperty'), [
|
|
compileValue(this.name.name, cx)
|
|
]);
|
|
} else if (this.flags & IR.Flags.RESOLVED) {
|
|
return call(property(object, 'asGetResolvedStringProperty'), [
|
|
compileValue(this.name, cx)
|
|
]);
|
|
}
|
|
var name = compileMultiname(this.name, cx);
|
|
var isMethod = new Literal(this.flags & IR.Flags.IS_METHOD);
|
|
return call(property(object, 'asGetProperty'), name.concat(isMethod));
|
|
};
|
|
IR.ASGetSuper.prototype.compile = function (cx) {
|
|
var scope = compileValue(this.scope, cx);
|
|
var object = compileValue(this.object, cx);
|
|
var name = compileMultiname(this.name, cx);
|
|
return call(property(object, 'asGetSuper'), [
|
|
scope
|
|
].concat(name));
|
|
};
|
|
IR.Latch.prototype.compile = function (cx) {
|
|
return new ConditionalExpression(compileValue(this.condition, cx), compileValue(this.left, cx), compileValue(this.right, cx));
|
|
};
|
|
IR.Unary.prototype.compile = function (cx) {
|
|
return new UnaryExpression(this.operator.name, compileValue(this.argument, cx));
|
|
};
|
|
IR.Copy.prototype.compile = function (cx) {
|
|
return compileValue(this.argument, cx);
|
|
};
|
|
IR.Binary.prototype.compile = function (cx) {
|
|
var left = compileValue(this.left, cx);
|
|
var right = compileValue(this.right, cx);
|
|
if (this.operator === Operator.AS_ADD) {
|
|
return call(id('asAdd'), [
|
|
left,
|
|
right
|
|
]);
|
|
}
|
|
return new BinaryExpression(this.operator.name, left, right);
|
|
};
|
|
IR.CallProperty.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
var name = compileValue(this.name, cx);
|
|
var callee = property(object, name);
|
|
var args = this.args.map(function (arg) {
|
|
return compileValue(arg, cx);
|
|
});
|
|
if (this.flags & IR.Flags.PRISTINE) {
|
|
return call(callee, args);
|
|
} else {
|
|
return callCall(callee, object, args);
|
|
}
|
|
};
|
|
IR.ASCallProperty.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
var args = this.args.map(function (arg) {
|
|
return compileValue(arg, cx);
|
|
});
|
|
if (this.flags & IR.Flags.RESOLVED) {
|
|
return call(property(object, 'asCallResolvedStringProperty'), [
|
|
compileValue(this.name, cx),
|
|
new Literal(this.isLex),
|
|
new ArrayExpression(args)
|
|
]);
|
|
}
|
|
var name = compileMultiname(this.name, cx);
|
|
return call(property(object, 'asCallProperty'), name.concat([
|
|
new Literal(this.isLex),
|
|
new ArrayExpression(args)
|
|
]));
|
|
};
|
|
IR.ASCallSuper.prototype.compile = function (cx) {
|
|
var scope = compileValue(this.scope, cx);
|
|
var object = compileValue(this.object, cx);
|
|
var args = this.args.map(function (arg) {
|
|
return compileValue(arg, cx);
|
|
});
|
|
var name = compileMultiname(this.name, cx);
|
|
return call(property(object, 'asCallSuper'), [
|
|
scope
|
|
].concat(name).concat(new ArrayExpression(args)));
|
|
};
|
|
IR.Call.prototype.compile = function (cx) {
|
|
var args = this.args.map(function (arg) {
|
|
return compileValue(arg, cx);
|
|
});
|
|
var callee = compileValue(this.callee, cx);
|
|
var object;
|
|
if (this.object) {
|
|
object = compileValue(this.object, cx);
|
|
} else {
|
|
object = new Literal(null);
|
|
}
|
|
if (false && this.pristine && (this.callee instanceof IR.GetProperty && this.callee.object === this.object) || this.object === null) {
|
|
return call(callee, args);
|
|
} else {
|
|
return callCall(callee, object, args);
|
|
}
|
|
};
|
|
IR.ASNew.prototype.compile = function (cx) {
|
|
var args = this.args.map(function (arg) {
|
|
return compileValue(arg, cx);
|
|
});
|
|
var callee = compileValue(this.callee, cx);
|
|
callee = property(callee, 'instanceConstructor');
|
|
return new NewExpression(callee, args);
|
|
};
|
|
IR.This.prototype.compile = function (cx) {
|
|
return new ThisExpression();
|
|
};
|
|
IR.Throw.prototype.compile = function (cx) {
|
|
var argument = compileValue(this.argument, cx);
|
|
return new ThrowStatement(argument);
|
|
};
|
|
IR.Arguments.prototype.compile = function (cx) {
|
|
return id('arguments');
|
|
};
|
|
IR.ASGlobal.prototype.compile = function (cx) {
|
|
var scope = compileValue(this.scope, cx);
|
|
return property(scope, 'global', 'object');
|
|
};
|
|
IR.ASSetProperty.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
var value = compileValue(this.value, cx);
|
|
if (this.flags & IR.Flags.INDEXED) {
|
|
return call(property(object, 'asSetNumericProperty'), [
|
|
compileValue(this.name.name, cx),
|
|
value
|
|
]);
|
|
}
|
|
var name = compileMultiname(this.name, cx);
|
|
return call(property(object, 'asSetProperty'), name.concat(value));
|
|
};
|
|
IR.ASSetSuper.prototype.compile = function (cx) {
|
|
var scope = compileValue(this.scope, cx);
|
|
var object = compileValue(this.object, cx);
|
|
var name = compileMultiname(this.name, cx);
|
|
var value = compileValue(this.value, cx);
|
|
return call(property(object, 'asSetSuper'), [
|
|
scope
|
|
].concat(name).concat([
|
|
value
|
|
]));
|
|
};
|
|
IR.ASDeleteProperty.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
var name = compileMultiname(this.name, cx);
|
|
return call(property(object, 'asDeleteProperty'), name);
|
|
};
|
|
IR.ASHasProperty.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
var name = compileMultiname(this.name, cx);
|
|
return call(property(object, 'asHasProperty'), name);
|
|
};
|
|
IR.GlobalProperty.prototype.compile = function (cx) {
|
|
return id(this.name);
|
|
};
|
|
IR.GetProperty.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
var name = compileValue(this.name, cx);
|
|
return property(object, name);
|
|
};
|
|
IR.SetProperty.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
var name = compileValue(this.name, cx);
|
|
var value = compileValue(this.value, cx);
|
|
return assignment(property(object, name), value);
|
|
};
|
|
IR.ASGetDescendants.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
var name = compileValue(this.name, cx);
|
|
return call(id('getDescendants'), [
|
|
object,
|
|
name
|
|
]);
|
|
};
|
|
IR.ASSetSlot.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
var name = compileValue(this.name, cx);
|
|
var value = compileValue(this.value, cx);
|
|
return call(id('asSetSlot'), [
|
|
object,
|
|
name,
|
|
value
|
|
]);
|
|
};
|
|
IR.ASGetSlot.prototype.compile = function (cx) {
|
|
var object = compileValue(this.object, cx);
|
|
var name = compileValue(this.name, cx);
|
|
return call(id('asGetSlot'), [
|
|
object,
|
|
name
|
|
]);
|
|
};
|
|
IR.Projection.prototype.compile = function (cx) {
|
|
true;
|
|
true;
|
|
return compileValue(this.argument.scope, cx);
|
|
};
|
|
IR.NewArray.prototype.compile = function (cx) {
|
|
return new ArrayExpression(compileValues(this.elements, cx));
|
|
};
|
|
IR.NewObject.prototype.compile = function (cx) {
|
|
var properties = this.properties.map(function (property) {
|
|
var key = compileValue(property.key, cx);
|
|
var value = compileValue(property.value, cx);
|
|
return new Property(key, value, 'init');
|
|
});
|
|
return new ObjectExpression(properties);
|
|
};
|
|
IR.ASNewActivation.prototype.compile = function (cx) {
|
|
var methodInfo = compileValue(this.methodInfo, cx);
|
|
return call(id('asCreateActivation'), [
|
|
methodInfo
|
|
]);
|
|
};
|
|
IR.ASMultiname.prototype.compile = function (cx) {
|
|
var namespaces = compileValue(this.namespaces, cx);
|
|
var name = compileValue(this.name, cx);
|
|
return call(id('createName'), [
|
|
namespaces,
|
|
name
|
|
]);
|
|
};
|
|
function generateSource(node) {
|
|
return escodegen.generate(node, {
|
|
base: '',
|
|
indent: ' ',
|
|
comment: true,
|
|
format: {
|
|
compact: false
|
|
}
|
|
});
|
|
}
|
|
function generate(cfg, useRegisterAllocator) {
|
|
Timer.start('Looper');
|
|
var root = Looper.analyze(cfg);
|
|
Timer.stop();
|
|
var writer = new IndentingWriter();
|
|
var cx = new Context();
|
|
Timer.start('Construct AST');
|
|
var code = root.compile(cx);
|
|
Timer.stop();
|
|
var parameters = [];
|
|
for (var i = 0; i < cx.parameters.length; i++) {
|
|
var name = cx.parameters[i] ? cx.parameters[i].name : '_' + i;
|
|
parameters.push(id(name));
|
|
}
|
|
if (cx.variables.length) {
|
|
Counter.count('Backend: Locals', cx.variables.length);
|
|
var variables = variableDeclaration(cx.variables.map(function (variable) {
|
|
return new VariableDeclarator(id(variable.name));
|
|
}));
|
|
code.body.unshift(variables);
|
|
}
|
|
var node = new FunctionDeclaration(id('fn'), parameters, code);
|
|
if (useRegisterAllocator) {
|
|
if (c4TraceLevel.value > 0) {
|
|
writer.writeLn('=== BEFORE ===============================');
|
|
writer.writeLn(generateSource(node));
|
|
writer.writeLn('=== TRANSFORMING =========================');
|
|
}
|
|
Transform.transform(node);
|
|
if (c4TraceLevel.value > 0) {
|
|
writer.writeLn('=== AFTER ================================');
|
|
writer.writeLn(generateSource(node));
|
|
writer.writeLn('==========================================');
|
|
}
|
|
var body = generateSource(code);
|
|
return {
|
|
parameters: parameters.map(function (p) {
|
|
return p.name;
|
|
}),
|
|
body: body
|
|
};
|
|
}
|
|
Timer.start('Serialize AST');
|
|
var source = generateSource(code);
|
|
Timer.stop();
|
|
return {
|
|
parameters: parameters.map(function (p) {
|
|
return p.name;
|
|
}),
|
|
body: source
|
|
};
|
|
}
|
|
Backend.generate = generate;
|
|
}(typeof exports === 'undefined' ? Backend = {} : exports));
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
(function (Runtime) {
|
|
var Multiname = Shumway.AVM2.ABC.Multiname;
|
|
var Namespace = Shumway.AVM2.ABC.Namespace;
|
|
var ClassInfo = Shumway.AVM2.ABC.ClassInfo;
|
|
var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo;
|
|
var Trait = Shumway.AVM2.ABC.Trait;
|
|
var IndentingWriter = Shumway.IndentingWriter;
|
|
var createMap = Shumway.ObjectUtilities.createMap;
|
|
var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter;
|
|
var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty;
|
|
var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty;
|
|
var bindSafely = Shumway.FunctionUtilities.bindSafely;
|
|
var vmNextTrampolineId = 1;
|
|
var vmNextMemoizerId = 1;
|
|
function getMethodOverrideKey(methodInfo) {
|
|
var key;
|
|
if (methodInfo.holder instanceof ClassInfo) {
|
|
key = 'static ' + methodInfo.holder.instanceInfo.name.getOriginalName() + '::' + methodInfo.name.getOriginalName();
|
|
} else if (methodInfo.holder instanceof InstanceInfo) {
|
|
key = methodInfo.holder.name.getOriginalName() + '::' + methodInfo.name.getOriginalName();
|
|
} else {
|
|
key = methodInfo.name.getOriginalName();
|
|
}
|
|
return key;
|
|
}
|
|
Runtime.getMethodOverrideKey = getMethodOverrideKey;
|
|
function checkMethodOverrides(methodInfo) {
|
|
if (methodInfo.name) {
|
|
var key = getMethodOverrideKey(methodInfo);
|
|
if (key in Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES) {
|
|
Shumway.Debug.warning('Overriding Method: ' + key);
|
|
return Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES[key];
|
|
}
|
|
}
|
|
}
|
|
Runtime.checkMethodOverrides = checkMethodOverrides;
|
|
function makeTrampoline(forward, parameterLength, description) {
|
|
true;
|
|
return function trampolineContext() {
|
|
var target = null;
|
|
var trampoline = function execute() {
|
|
if (Shumway.AVM2.Runtime.traceExecution.value >= 3) {
|
|
log('Trampolining');
|
|
}
|
|
Counter.count('Executing Trampoline');
|
|
Shumway.AVM2.Runtime.traceCallExecution.value > 1 && callWriter.writeLn('Trampoline: ' + description);
|
|
if (!target) {
|
|
target = forward(trampoline);
|
|
true;
|
|
}
|
|
return target.apply(this, arguments);
|
|
};
|
|
trampoline.trigger = function trigger() {
|
|
Counter.count('Triggering Trampoline');
|
|
if (!target) {
|
|
target = forward(trampoline);
|
|
true;
|
|
}
|
|
};
|
|
trampoline.isTrampoline = true;
|
|
trampoline.debugName = 'Trampoline #' + vmNextTrampolineId++;
|
|
defineReadOnlyProperty(trampoline, Shumway.AVM2.Runtime.VM_LENGTH, parameterLength);
|
|
return trampoline;
|
|
}();
|
|
}
|
|
Runtime.makeTrampoline = makeTrampoline;
|
|
function makeMemoizer(qn, target) {
|
|
function memoizer() {
|
|
Counter.count('Runtime: Memoizing');
|
|
if (Shumway.AVM2.Runtime.traceExecution.value >= 3) {
|
|
log('Memoizing: ' + qn);
|
|
}
|
|
Shumway.AVM2.Runtime.traceCallExecution.value > 1 && callWriter.writeLn('Memoizing: ' + qn);
|
|
if (Shumway.AVM2.Runtime.isNativePrototype(this)) {
|
|
Counter.count('Runtime: Method Closures');
|
|
return bindSafely(target.value, this);
|
|
}
|
|
if (isTrampoline(target.value)) {
|
|
target.value.trigger();
|
|
}
|
|
true;
|
|
var mc = null;
|
|
if (Shumway.AVM2.Runtime.isClass(this)) {
|
|
Counter.count('Runtime: Static Method Closures');
|
|
mc = bindSafely(target.value, this);
|
|
defineReadOnlyProperty(this, qn, mc);
|
|
return mc;
|
|
}
|
|
if (Object.prototype.hasOwnProperty.call(this, qn)) {
|
|
var pd = Object.getOwnPropertyDescriptor(this, qn);
|
|
if (pd.get) {
|
|
Counter.count('Runtime: Method Closures');
|
|
return bindSafely(target.value, this);
|
|
}
|
|
Counter.count('Runtime: Unpatched Memoizer');
|
|
return this[qn];
|
|
}
|
|
mc = bindSafely(target.value, this);
|
|
mc.methodInfo = target.value.methodInfo;
|
|
defineReadOnlyProperty(mc, Multiname.getPublicQualifiedName('prototype'), null);
|
|
defineReadOnlyProperty(this, qn, mc);
|
|
return mc;
|
|
}
|
|
var m = memoizer;
|
|
Counter.count('Runtime: Memoizers');
|
|
m.isMemoizer = true;
|
|
m.debugName = 'Memoizer #' + vmNextMemoizerId++;
|
|
return m;
|
|
}
|
|
Runtime.makeMemoizer = makeMemoizer;
|
|
function isTrampoline(fn) {
|
|
true;
|
|
return fn.isTrampoline;
|
|
}
|
|
Runtime.isTrampoline = isTrampoline;
|
|
function isMemoizer(fn) {
|
|
true;
|
|
return fn.isMemoizer;
|
|
}
|
|
Runtime.isMemoizer = isMemoizer;
|
|
}(AVM2.Runtime || (AVM2.Runtime = {})));
|
|
var Runtime = AVM2.Runtime;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
var __extends = this.__extends || function (d, b) {
|
|
for (var p in b)
|
|
if (b.hasOwnProperty(p))
|
|
d[p] = b[p];
|
|
function __() {
|
|
this.constructor = d;
|
|
}
|
|
__.prototype = b.prototype;
|
|
d.prototype = new __();
|
|
};
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
(function (Runtime) {
|
|
var Multiname = Shumway.AVM2.ABC.Multiname;
|
|
var Namespace = Shumway.AVM2.ABC.Namespace;
|
|
var MethodInfo = Shumway.AVM2.ABC.MethodInfo;
|
|
var ClassInfo = Shumway.AVM2.ABC.ClassInfo;
|
|
var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo;
|
|
var ScriptInfo = Shumway.AVM2.ABC.ScriptInfo;
|
|
var Trait = Shumway.AVM2.ABC.Trait;
|
|
var IndentingWriter = Shumway.IndentingWriter;
|
|
var hasOwnProperty = Shumway.ObjectUtilities.hasOwnProperty;
|
|
var createMap = Shumway.ObjectUtilities.createMap;
|
|
var cloneObject = Shumway.ObjectUtilities.cloneObject;
|
|
var copyProperties = Shumway.ObjectUtilities.copyProperties;
|
|
var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject;
|
|
var bindSafely = Shumway.FunctionUtilities.bindSafely;
|
|
var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter;
|
|
var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty;
|
|
var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty;
|
|
var defineNonEnumerableGetter = Shumway.ObjectUtilities.defineNonEnumerableGetter;
|
|
var makeForwardingGetter = Shumway.FunctionUtilities.makeForwardingGetter;
|
|
var makeForwardingSetter = Shumway.FunctionUtilities.makeForwardingSetter;
|
|
var Binding = function () {
|
|
function Binding(trait) {
|
|
this.trait = trait;
|
|
}
|
|
Binding.getKey = function (qn, trait) {
|
|
var key = qn;
|
|
if (trait.isGetter()) {
|
|
key = Binding.GET_PREFIX + qn;
|
|
} else if (trait.isSetter()) {
|
|
key = Binding.SET_PREFIX + qn;
|
|
}
|
|
return key;
|
|
};
|
|
Binding.prototype.toString = function () {
|
|
return String(this.trait);
|
|
};
|
|
Binding.SET_PREFIX = 'set ';
|
|
Binding.GET_PREFIX = 'get ';
|
|
Binding.KEY_PREFIX_LENGTH = 4;
|
|
return Binding;
|
|
}();
|
|
Runtime.Binding = Binding;
|
|
var SlotInfo = function () {
|
|
function SlotInfo(name, isConst, type, trait) {
|
|
this.name = name;
|
|
this.isConst = isConst;
|
|
this.type = type;
|
|
this.trait = trait;
|
|
}
|
|
return SlotInfo;
|
|
}();
|
|
Runtime.SlotInfo = SlotInfo;
|
|
var SlotInfoMap = function () {
|
|
function SlotInfoMap() {
|
|
this.byID = createMap();
|
|
this.byQN = createMap();
|
|
}
|
|
return SlotInfoMap;
|
|
}();
|
|
Runtime.SlotInfoMap = SlotInfoMap;
|
|
var Bindings = function () {
|
|
function Bindings() {
|
|
this.map = createMap();
|
|
this.slots = [];
|
|
this.nextSlotId = 1;
|
|
}
|
|
Bindings.prototype.assignNextSlot = function (trait) {
|
|
true;
|
|
true;
|
|
if (!trait.slotId) {
|
|
trait.slotId = this.nextSlotId++;
|
|
} else {
|
|
this.nextSlotId = trait.slotId + 1;
|
|
}
|
|
true;
|
|
this.slots[trait.slotId] = trait;
|
|
};
|
|
Bindings.prototype.trace = function (writer) {
|
|
writer.enter('Bindings');
|
|
for (var key in this.map) {
|
|
var binding = this.map[key];
|
|
writer.writeLn(binding.trait.kindName() + ': ' + key + ' -> ' + binding);
|
|
}
|
|
writer.leaveAndEnter('Slots');
|
|
writer.writeArray(this.slots);
|
|
writer.outdent();
|
|
};
|
|
Bindings.prototype.applyTo = function (domain, object) {
|
|
true;
|
|
true;
|
|
true;
|
|
defineNonEnumerableProperty(object, Shumway.AVM2.Runtime.VM_SLOTS, new SlotInfoMap());
|
|
defineNonEnumerableProperty(object, Shumway.AVM2.Runtime.VM_BINDINGS, []);
|
|
defineNonEnumerableProperty(object, Shumway.AVM2.Runtime.VM_OPEN_METHODS, createMap());
|
|
defineNonEnumerableProperty(object, 'bindings', this);
|
|
defineNonEnumerableProperty(object, 'resolutionMap', []);
|
|
traitsWriter && traitsWriter.greenLn('Applying Traits');
|
|
for (var key in this.map) {
|
|
var binding = this.map[key];
|
|
var trait = binding.trait;
|
|
var qn = Multiname.getQualifiedName(trait.name);
|
|
if (trait.isSlot() || trait.isConst() || trait.isClass()) {
|
|
var defaultValue = undefined;
|
|
if (trait.isSlot() || trait.isConst()) {
|
|
if (trait.hasDefaultValue) {
|
|
defaultValue = trait.value;
|
|
} else if (trait.typeName) {
|
|
defaultValue = domain.findClassInfo(trait.typeName).defaultValue;
|
|
}
|
|
}
|
|
if (key !== qn) {
|
|
traitsWriter && traitsWriter.yellowLn('Binding Trait: ' + key + ' -> ' + qn);
|
|
defineNonEnumerableGetter(object, key, makeForwardingGetter(qn));
|
|
object.asBindings.pushUnique(key);
|
|
} else {
|
|
traitsWriter && traitsWriter.greenLn('Applying Trait ' + trait.kindName() + ': ' + trait);
|
|
defineNonEnumerableProperty(object, qn, defaultValue);
|
|
object.asBindings.pushUnique(qn);
|
|
var slotInfo = new SlotInfo(qn, trait.isConst(), trait.typeName ? domain.getProperty(trait.typeName, false, false) : null, trait);
|
|
object.asSlots.byID[trait.slotId] = slotInfo;
|
|
object.asSlots.byQN[qn] = slotInfo;
|
|
}
|
|
} else if (trait.isMethod() || trait.isGetter() || trait.isSetter()) {
|
|
if (trait.isGetter() || trait.isSetter()) {
|
|
key = key.substring(Binding.KEY_PREFIX_LENGTH);
|
|
}
|
|
if (key !== qn) {
|
|
traitsWriter && traitsWriter.yellowLn('Binding Trait: ' + key + ' -> ' + qn);
|
|
} else {
|
|
traitsWriter && traitsWriter.greenLn('Applying Trait ' + trait.kindName() + ': ' + trait);
|
|
}
|
|
object.asBindings.pushUnique(key);
|
|
if (this instanceof ScriptBindings) {
|
|
Shumway.AVM2.Runtime.applyNonMemoizedMethodTrait(key, trait, object, binding.scope, binding.natives);
|
|
} else {
|
|
Shumway.AVM2.Runtime.applyMemoizedMethodTrait(key, trait, object, binding.scope, binding.natives);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return Bindings;
|
|
}();
|
|
Runtime.Bindings = Bindings;
|
|
var ActivationBindings = function (_super) {
|
|
__extends(ActivationBindings, _super);
|
|
function ActivationBindings(methodInfo) {
|
|
_super.call(this);
|
|
true;
|
|
this.methodInfo = methodInfo;
|
|
var traits = methodInfo.traits;
|
|
for (var i = 0; i < traits.length; i++) {
|
|
var trait = traits[i];
|
|
true;
|
|
var key = Multiname.getQualifiedName(trait.name);
|
|
this.map[key] = new Binding(trait);
|
|
this.assignNextSlot(trait);
|
|
}
|
|
}
|
|
return ActivationBindings;
|
|
}(Bindings);
|
|
Runtime.ActivationBindings = ActivationBindings;
|
|
var CatchBindings = function (_super) {
|
|
__extends(CatchBindings, _super);
|
|
function CatchBindings(scope, trait) {
|
|
_super.call(this);
|
|
var key = Multiname.getQualifiedName(trait.name);
|
|
this.map[key] = new Binding(trait);
|
|
true;
|
|
this.assignNextSlot(trait);
|
|
}
|
|
return CatchBindings;
|
|
}(Bindings);
|
|
Runtime.CatchBindings = CatchBindings;
|
|
var ScriptBindings = function (_super) {
|
|
__extends(ScriptBindings, _super);
|
|
function ScriptBindings(scriptInfo, scope) {
|
|
_super.call(this);
|
|
this.scope = scope;
|
|
this.scriptInfo = scriptInfo;
|
|
var traits = scriptInfo.traits;
|
|
for (var i = 0; i < traits.length; i++) {
|
|
var trait = traits[i];
|
|
var name = Multiname.getQualifiedName(trait.name);
|
|
var key = Binding.getKey(name, trait);
|
|
var binding = this.map[key] = new Binding(trait);
|
|
if (trait.isSlot() || trait.isConst() || trait.isClass()) {
|
|
this.assignNextSlot(trait);
|
|
}
|
|
if (trait.isClass()) {
|
|
if (trait.metadata && trait.metadata.native) {
|
|
trait.classInfo.native = trait.metadata.native;
|
|
}
|
|
}
|
|
if (trait.isMethod() || trait.isGetter() || trait.isSetter()) {
|
|
binding.scope = this.scope;
|
|
}
|
|
}
|
|
}
|
|
return ScriptBindings;
|
|
}(Bindings);
|
|
Runtime.ScriptBindings = ScriptBindings;
|
|
var ClassBindings = function (_super) {
|
|
__extends(ClassBindings, _super);
|
|
function ClassBindings(classInfo, scope, natives) {
|
|
_super.call(this);
|
|
this.scope = scope;
|
|
this.natives = natives;
|
|
this.classInfo = classInfo;
|
|
var traits = classInfo.traits;
|
|
for (var i = 0; i < traits.length; i++) {
|
|
var trait = traits[i];
|
|
var name = Multiname.getQualifiedName(trait.name);
|
|
var key = Binding.getKey(name, trait);
|
|
var binding = this.map[key] = new Binding(trait);
|
|
if (trait.isSlot() || trait.isConst()) {
|
|
this.assignNextSlot(trait);
|
|
}
|
|
if (trait.isMethod() || trait.isGetter() || trait.isSetter()) {
|
|
binding.scope = this.scope;
|
|
binding.natives = this.natives;
|
|
}
|
|
}
|
|
}
|
|
return ClassBindings;
|
|
}(Bindings);
|
|
Runtime.ClassBindings = ClassBindings;
|
|
var InstanceBindings = function (_super) {
|
|
__extends(InstanceBindings, _super);
|
|
function InstanceBindings(parent, instanceInfo, scope, natives) {
|
|
_super.call(this);
|
|
this.scope = scope;
|
|
this.natives = natives;
|
|
this.parent = parent;
|
|
this.instanceInfo = instanceInfo;
|
|
this.implementedInterfaces = parent ? cloneObject(parent.implementedInterfaces) : createEmptyObject();
|
|
if (parent) {
|
|
this.slots = parent.slots.slice();
|
|
this.nextSlotId = parent.nextSlotId;
|
|
}
|
|
this.extend(parent);
|
|
}
|
|
InstanceBindings.prototype.extend = function (parent) {
|
|
var ii = this.instanceInfo, ib;
|
|
var map = this.map;
|
|
var name, key, trait, binding, protectedName, protectedKey;
|
|
if (parent) {
|
|
for (key in parent.map) {
|
|
binding = parent.map[key];
|
|
trait = binding.trait;
|
|
map[key] = binding;
|
|
if (trait.isProtected()) {
|
|
protectedName = Multiname.getQualifiedName(new Multiname([
|
|
ii.protectedNs
|
|
], trait.name.getName()));
|
|
protectedKey = Binding.getKey(protectedName, trait);
|
|
map[protectedKey] = binding;
|
|
}
|
|
}
|
|
}
|
|
function writeOrOverwriteBinding(object, key, binding) {
|
|
var trait = binding.trait;
|
|
var oldBinding = object[key];
|
|
if (oldBinding) {
|
|
var oldTrait = oldBinding.trait;
|
|
true;
|
|
true;
|
|
} else {
|
|
true;
|
|
}
|
|
object[key] = binding;
|
|
}
|
|
function overwriteProtectedBinding(object, key, binding) {
|
|
if (key in object) {
|
|
object[key] = binding;
|
|
}
|
|
}
|
|
var traits = ii.traits;
|
|
for (var i = 0; i < traits.length; i++) {
|
|
trait = traits[i];
|
|
name = Multiname.getQualifiedName(trait.name);
|
|
key = Binding.getKey(name, trait);
|
|
binding = new Binding(trait);
|
|
writeOrOverwriteBinding(map, key, binding);
|
|
if (trait.isProtected()) {
|
|
ib = this.parent;
|
|
while (ib) {
|
|
protectedName = Multiname.getQualifiedName(new Multiname([
|
|
ib.instanceInfo.protectedNs
|
|
], trait.name.getName()));
|
|
protectedKey = Binding.getKey(protectedName, trait);
|
|
overwriteProtectedBinding(map, protectedKey, binding);
|
|
ib = ib.parent;
|
|
}
|
|
}
|
|
if (trait.isSlot() || trait.isConst()) {
|
|
this.assignNextSlot(trait);
|
|
}
|
|
if (trait.isMethod() || trait.isGetter() || trait.isSetter()) {
|
|
binding.scope = this.scope;
|
|
binding.natives = this.natives;
|
|
}
|
|
}
|
|
var domain = ii.abc.applicationDomain;
|
|
var interfaces = ii.interfaces;
|
|
for (var i = 0; i < interfaces.length; i++) {
|
|
var interface = domain.getProperty(interfaces[i], true, true);
|
|
true;
|
|
copyProperties(this.implementedInterfaces, interface.interfaceBindings.implementedInterfaces);
|
|
this.implementedInterfaces[Multiname.getQualifiedName(interface.name)] = interface;
|
|
}
|
|
for (var interfaceName in this.implementedInterfaces) {
|
|
var interface = this.implementedInterfaces[interfaceName];
|
|
ib = interface.interfaceBindings;
|
|
for (var interfaceKey in ib.map) {
|
|
var interfaceBinding = ib.map[interfaceKey];
|
|
if (ii.isInterface()) {
|
|
map[interfaceKey] = interfaceBinding;
|
|
} else {
|
|
name = Multiname.getPublicQualifiedName(interfaceBinding.trait.name.getName());
|
|
key = Binding.getKey(name, interfaceBinding.trait);
|
|
map[interfaceKey] = map[key];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
InstanceBindings.prototype.toString = function () {
|
|
return this.instanceInfo.toString();
|
|
};
|
|
return InstanceBindings;
|
|
}(Bindings);
|
|
Runtime.InstanceBindings = InstanceBindings;
|
|
var traitsWriter = null;
|
|
}(AVM2.Runtime || (AVM2.Runtime = {})));
|
|
var Runtime = AVM2.Runtime;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
var Binding = Shumway.AVM2.Runtime.Binding;
|
|
var Bindings = Shumway.AVM2.Runtime.Bindings;
|
|
var ActivationBindings = Shumway.AVM2.Runtime.ActivationBindings;
|
|
var CatchBindings = Shumway.AVM2.Runtime.CatchBindings;
|
|
var ScriptBindings = Shumway.AVM2.Runtime.ScriptBindings;
|
|
var ClassBindings = Shumway.AVM2.Runtime.ClassBindings;
|
|
var InstanceBindings = Shumway.AVM2.Runtime.InstanceBindings;
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
(function (Runtime) {
|
|
var Multiname = Shumway.AVM2.ABC.Multiname;
|
|
var Namespace = Shumway.AVM2.ABC.Namespace;
|
|
var MethodInfo = Shumway.AVM2.ABC.MethodInfo;
|
|
var ClassInfo = Shumway.AVM2.ABC.ClassInfo;
|
|
var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo;
|
|
var InstanceBindings = Shumway.AVM2.Runtime.InstanceBindings;
|
|
var ClassBindings = Shumway.AVM2.Runtime.ClassBindings;
|
|
var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter;
|
|
var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty;
|
|
var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty;
|
|
var defineNonEnumerableGetter = Shumway.ObjectUtilities.defineNonEnumerableGetter;
|
|
var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject;
|
|
var toKeyValueArray = Shumway.ObjectUtilities.toKeyValueArray;
|
|
var boxValue = Shumway.ObjectUtilities.boxValue;
|
|
function makeCacheKey(namespaces, name, flags) {
|
|
if (!namespaces) {
|
|
return name;
|
|
} else if (namespaces.length > 1) {
|
|
return namespaces.runtimeId + '$' + name;
|
|
} else {
|
|
return namespaces[0].qualifiedName + '$' + name;
|
|
}
|
|
}
|
|
var Scope = function () {
|
|
function Scope(parent, object, isWith) {
|
|
if (typeof isWith === 'undefined') {
|
|
isWith = false;
|
|
}
|
|
this.parent = parent;
|
|
this.object = boxValue(object);
|
|
true;
|
|
this.global = parent ? parent.global : this;
|
|
this.isWith = isWith;
|
|
this.cache = createEmptyObject();
|
|
}
|
|
Scope.prototype.findDepth = function (object) {
|
|
var current = this;
|
|
var depth = 0;
|
|
while (current) {
|
|
if (current.object === object) {
|
|
return depth;
|
|
}
|
|
depth++;
|
|
current = current.parent;
|
|
}
|
|
return -1;
|
|
};
|
|
Scope.prototype.getScopeObjects = function () {
|
|
var objects = [];
|
|
var current = this;
|
|
while (current) {
|
|
objects.unshift(current.object);
|
|
current = current.parent;
|
|
}
|
|
return objects;
|
|
};
|
|
Scope.prototype.findScopeProperty = function (namespaces, name, flags, domain, strict, scopeOnly) {
|
|
Counter.count('findScopeProperty');
|
|
var object;
|
|
var key = makeCacheKey(namespaces, name, flags);
|
|
if (!scopeOnly && (object = this.cache[key])) {
|
|
return object;
|
|
}
|
|
if (this.object.asHasProperty(namespaces, name, flags, true)) {
|
|
return this.isWith ? this.object : this.cache[key] = this.object;
|
|
}
|
|
if (this.parent) {
|
|
return this.cache[key] = this.parent.findScopeProperty(namespaces, name, flags, domain, strict, scopeOnly);
|
|
}
|
|
if (scopeOnly)
|
|
return null;
|
|
if (object = domain.findDomainProperty(new Multiname(namespaces, name, flags), strict, true)) {
|
|
return object;
|
|
}
|
|
if (strict) {
|
|
Shumway.Debug.unexpected('Cannot find property ' + name);
|
|
}
|
|
return this.global.object;
|
|
};
|
|
return Scope;
|
|
}();
|
|
Runtime.Scope = Scope;
|
|
function bindFreeMethodScope(methodInfo, scope) {
|
|
var fn = methodInfo.freeMethod;
|
|
if (methodInfo.lastBoundMethod && methodInfo.lastBoundMethod.scope === scope) {
|
|
return methodInfo.lastBoundMethod.boundMethod;
|
|
}
|
|
true;
|
|
var boundMethod;
|
|
var asGlobal = scope.global.object;
|
|
if (!methodInfo.hasOptional() && !methodInfo.needsArguments() && !methodInfo.needsRest()) {
|
|
switch (methodInfo.parameters.length) {
|
|
case 0:
|
|
boundMethod = function () {
|
|
return fn.call(this === jsGlobal ? asGlobal : this, scope);
|
|
};
|
|
break;
|
|
case 1:
|
|
boundMethod = function (x) {
|
|
return fn.call(this === jsGlobal ? asGlobal : this, scope, x);
|
|
};
|
|
break;
|
|
case 2:
|
|
boundMethod = function (x, y) {
|
|
return fn.call(this === jsGlobal ? asGlobal : this, scope, x, y);
|
|
};
|
|
break;
|
|
case 3:
|
|
boundMethod = function (x, y, z) {
|
|
return fn.call(this === jsGlobal ? asGlobal : this, scope, x, y, z);
|
|
};
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (!boundMethod) {
|
|
Counter.count('Bind Scope - Slow Path');
|
|
boundMethod = function () {
|
|
Array.prototype.unshift.call(arguments, scope);
|
|
var global = this === jsGlobal ? scope.global.object : this;
|
|
return fn.apply(global, arguments);
|
|
};
|
|
}
|
|
boundMethod.methodInfo = methodInfo;
|
|
boundMethod.instanceConstructor = boundMethod;
|
|
methodInfo.lastBoundMethod = {
|
|
scope: scope,
|
|
boundMethod: boundMethod
|
|
};
|
|
return boundMethod;
|
|
}
|
|
Runtime.bindFreeMethodScope = bindFreeMethodScope;
|
|
}(AVM2.Runtime || (AVM2.Runtime = {})));
|
|
var Runtime = AVM2.Runtime;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
var playerglobalLoadedPromise;
|
|
var playerglobal;
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
(function (Runtime) {
|
|
var AbcFile = Shumway.AVM2.ABC.AbcFile;
|
|
var Multiname = Shumway.AVM2.ABC.Multiname;
|
|
var Namespace = Shumway.AVM2.ABC.Namespace;
|
|
var MethodInfo = Shumway.AVM2.ABC.MethodInfo;
|
|
var ClassInfo = Shumway.AVM2.ABC.ClassInfo;
|
|
var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo;
|
|
var ScriptInfo = Shumway.AVM2.ABC.ScriptInfo;
|
|
var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject;
|
|
var IndentingWriter = Shumway.IndentingWriter;
|
|
(function (EXECUTION_MODE) {
|
|
EXECUTION_MODE[EXECUTION_MODE['INTERPRET'] = 1] = 'INTERPRET';
|
|
EXECUTION_MODE[EXECUTION_MODE['COMPILE'] = 2] = 'COMPILE';
|
|
}(Runtime.EXECUTION_MODE || (Runtime.EXECUTION_MODE = {})));
|
|
var EXECUTION_MODE = Runtime.EXECUTION_MODE;
|
|
function createNewCompartment() {
|
|
return newGlobal('new-compartment');
|
|
}
|
|
function executeScript(script) {
|
|
var abc = script.abc;
|
|
true;
|
|
var global = new Shumway.AVM2.Runtime.Global(script);
|
|
if (abc.applicationDomain.allowNatives) {
|
|
global[Multiname.getPublicQualifiedName('unsafeJSNative')] = getNative;
|
|
}
|
|
script.executing = true;
|
|
var scope = new Shumway.AVM2.Runtime.Scope(null, script.global);
|
|
createFunction(script.init, scope).call(script.global, false);
|
|
script.executed = true;
|
|
}
|
|
Runtime.executeScript = executeScript;
|
|
function ensureScriptIsExecuted(script, reason) {
|
|
if (typeof reason === 'undefined') {
|
|
reason = '';
|
|
}
|
|
if (!script.executed && !script.executing) {
|
|
if (Shumway.AVM2.Runtime.traceExecution.value >= 2) {
|
|
log('Executing Script For: ' + reason);
|
|
}
|
|
executeScript(script);
|
|
}
|
|
}
|
|
Runtime.ensureScriptIsExecuted = ensureScriptIsExecuted;
|
|
(function (Glue) {
|
|
Glue[Glue['PUBLIC_PROPERTIES'] = 1] = 'PUBLIC_PROPERTIES';
|
|
Glue[Glue['PUBLIC_METHODS'] = 2] = 'PUBLIC_METHODS';
|
|
Glue[Glue['ALL'] = 1 | 2] = 'ALL';
|
|
}(Runtime.Glue || (Runtime.Glue = {})));
|
|
var Glue = Runtime.Glue;
|
|
function grabAbc(abcName) {
|
|
var entry = playerglobal.scripts[abcName];
|
|
if (!entry) {
|
|
return null;
|
|
}
|
|
var offset = entry.offset;
|
|
var length = entry.length;
|
|
return new AbcFile(new Uint8Array(playerglobal.abcs, offset, length), abcName);
|
|
}
|
|
function findDefiningAbc(mn) {
|
|
if (!playerglobal) {
|
|
return null;
|
|
}
|
|
for (var i = 0; i < mn.namespaces.length; i++) {
|
|
var name = mn.namespaces[i].uri + ':' + mn.name;
|
|
var abcName = playerglobal.map[name];
|
|
if (abcName) {
|
|
break;
|
|
}
|
|
}
|
|
if (abcName) {
|
|
return grabAbc(abcName);
|
|
}
|
|
return null;
|
|
}
|
|
function promiseFile(path, responseType) {
|
|
return new Promise(function (resolve, reject) {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('GET', path);
|
|
xhr.responseType = responseType;
|
|
xhr.onload = function () {
|
|
if (xhr.response) {
|
|
resolve(xhr.response);
|
|
} else {
|
|
reject('Unable to load ' + path + ': ' + xhr.statusText);
|
|
}
|
|
};
|
|
xhr.send();
|
|
});
|
|
}
|
|
var AVM2 = function () {
|
|
function AVM2(sysMode, appMode, loadAVM1) {
|
|
this.systemDomain = new ApplicationDomain(this, null, sysMode, true);
|
|
this.applicationDomain = new ApplicationDomain(this, this.systemDomain, appMode, false);
|
|
this.findDefiningAbc = findDefiningAbc;
|
|
this.loadAVM1 = loadAVM1;
|
|
this.isAVM1Loaded = false;
|
|
this.exception = {
|
|
value: undefined
|
|
};
|
|
this.exceptions = [];
|
|
}
|
|
AVM2.initialize = function (sysMode, appMode, loadAVM1) {
|
|
AVM2.instance = new AVM2(sysMode, appMode, loadAVM1);
|
|
};
|
|
AVM2.currentAbc = function () {
|
|
var caller = arguments.callee;
|
|
var maxDepth = 20;
|
|
var abc = null;
|
|
for (var i = 0; i < maxDepth && caller; i++) {
|
|
var mi = caller.methodInfo;
|
|
if (mi) {
|
|
abc = mi.abc;
|
|
break;
|
|
}
|
|
caller = caller.caller;
|
|
}
|
|
return abc;
|
|
};
|
|
AVM2.currentDomain = function () {
|
|
var abc = AVM2.currentAbc();
|
|
return abc.applicationDomain;
|
|
};
|
|
AVM2.isPlayerglobalLoaded = function () {
|
|
return !(!playerglobal);
|
|
};
|
|
AVM2.loadPlayerglobal = function (abcsPath, catalogPath) {
|
|
if (playerglobalLoadedPromise) {
|
|
return Promise.reject('Playerglobal is already loaded');
|
|
}
|
|
playerglobalLoadedPromise = Promise.all([
|
|
promiseFile(abcsPath, 'arraybuffer'),
|
|
promiseFile(catalogPath, 'json')
|
|
]).then(function (result) {
|
|
playerglobal = {
|
|
abcs: result[0],
|
|
map: Object.create(null),
|
|
scripts: Object.create(null)
|
|
};
|
|
var catalog = result[1];
|
|
for (var i = 0; i < catalog.length; i++) {
|
|
var abc = catalog[i];
|
|
playerglobal.scripts[abc.name] = abc;
|
|
if (typeof abc.defs === 'string') {
|
|
playerglobal.map[abc.defs] = abc.name;
|
|
} else {
|
|
for (var j = 0; j < abc.defs.length; j++) {
|
|
var def = abc.defs[j];
|
|
playerglobal.map[def] = abc.name;
|
|
}
|
|
}
|
|
}
|
|
}, function (e) {
|
|
console.error(e);
|
|
});
|
|
return playerglobalLoadedPromise;
|
|
};
|
|
AVM2.prototype.notifyConstruct = function (instanceConstructor, args) {
|
|
};
|
|
AVM2.getStackTrace = function () {
|
|
Shumway.Debug.notImplemented('getStackTrace');
|
|
};
|
|
return AVM2;
|
|
}();
|
|
Runtime.AVM2 = AVM2;
|
|
var ApplicationDomain = function () {
|
|
function ApplicationDomain(vm, base, mode, allowNatives) {
|
|
true;
|
|
true;
|
|
this.vm = vm;
|
|
this.abcs = [];
|
|
this.loadedAbcs = {};
|
|
this.loadedClasses = [];
|
|
this.classCache = createEmptyObject();
|
|
this.scriptCache = createEmptyObject();
|
|
this.classInfoCache = createEmptyObject();
|
|
this.base = base;
|
|
this.allowNatives = allowNatives;
|
|
this.mode = mode;
|
|
this.onMessage = new Callback();
|
|
if (base) {
|
|
this.system = base.system;
|
|
} else {
|
|
this.system = this;
|
|
}
|
|
}
|
|
ApplicationDomain.passthroughCallable = function (f) {
|
|
return {
|
|
call: function ($this) {
|
|
Array.prototype.shift.call(arguments);
|
|
return f.apply($this, arguments);
|
|
},
|
|
apply: function ($this, args) {
|
|
return f.apply($this, args);
|
|
}
|
|
};
|
|
};
|
|
ApplicationDomain.coerceCallable = function (type) {
|
|
return {
|
|
call: function ($this, value) {
|
|
return Shumway.AVM2.Runtime.asCoerce(type, value);
|
|
},
|
|
apply: function ($this, args) {
|
|
return Shumway.AVM2.Runtime.asCoerce(type, args[0]);
|
|
}
|
|
};
|
|
};
|
|
ApplicationDomain.constructingCallable = function (instanceConstructor) {
|
|
return {
|
|
call: function (self) {
|
|
return new (Function.bind.apply(instanceConstructor, arguments))();
|
|
},
|
|
apply: function (self, args) {
|
|
return new (Function.bind.apply(instanceConstructor, [
|
|
self
|
|
].concat(args)))();
|
|
}
|
|
};
|
|
};
|
|
ApplicationDomain.prototype.getType = function (multiname) {
|
|
return this.getProperty(multiname, true, true);
|
|
};
|
|
ApplicationDomain.prototype.getProperty = function (multiname, strict, execute) {
|
|
var resolved = this.findDefiningScript(multiname, execute);
|
|
if (resolved) {
|
|
if (!resolved.script.executing) {
|
|
return undefined;
|
|
}
|
|
return resolved.script.global[Multiname.getQualifiedName(resolved.trait.name)];
|
|
}
|
|
if (strict) {
|
|
return Shumway.Debug.unexpected('Cannot find property ' + multiname);
|
|
}
|
|
return undefined;
|
|
};
|
|
ApplicationDomain.prototype.getClass = function (simpleName) {
|
|
var cache = this.classCache;
|
|
var c = cache[simpleName];
|
|
if (!c) {
|
|
c = cache[simpleName] = this.getProperty(Multiname.fromSimpleName(simpleName), true, true);
|
|
}
|
|
true;
|
|
return c;
|
|
};
|
|
ApplicationDomain.prototype.findClass = function (simpleName) {
|
|
if (simpleName in this.classCache) {
|
|
return true;
|
|
}
|
|
return this.findDomainProperty(Multiname.fromSimpleName(simpleName), false, true);
|
|
};
|
|
ApplicationDomain.prototype.findDomainProperty = function (multiname, strict, execute) {
|
|
if (Shumway.AVM2.Runtime.traceDomain.value) {
|
|
log('ApplicationDomain.findDomainProperty: ' + multiname);
|
|
}
|
|
var resolved = this.findDefiningScript(multiname, execute);
|
|
if (resolved) {
|
|
return resolved.script.global;
|
|
}
|
|
if (strict) {
|
|
return Shumway.Debug.unexpected('Cannot find property ' + multiname);
|
|
} else {
|
|
return undefined;
|
|
}
|
|
return undefined;
|
|
};
|
|
ApplicationDomain.prototype.findClassInfo = function (mn) {
|
|
var originalQn;
|
|
if (Multiname.isQName(mn)) {
|
|
originalQn = Multiname.getQualifiedName(mn);
|
|
var ci = this.classInfoCache[originalQn];
|
|
if (ci) {
|
|
return ci;
|
|
}
|
|
} else {
|
|
var ci = this.classInfoCache[mn.runtimeId];
|
|
if (ci) {
|
|
return ci;
|
|
}
|
|
}
|
|
if (this.base) {
|
|
ci = this.base.findClassInfo(mn);
|
|
if (ci) {
|
|
return ci;
|
|
}
|
|
}
|
|
var abcs = this.abcs;
|
|
for (var i = 0; i < abcs.length; i++) {
|
|
var abc = abcs[i];
|
|
var scripts = abc.scripts;
|
|
for (var j = 0; j < scripts.length; j++) {
|
|
var script = scripts[j];
|
|
var traits = script.traits;
|
|
for (var k = 0; k < traits.length; k++) {
|
|
var trait = traits[k];
|
|
if (trait.isClass()) {
|
|
var traitName = Multiname.getQualifiedName(trait.name);
|
|
if (originalQn) {
|
|
if (traitName === originalQn) {
|
|
return this.classInfoCache[originalQn] = trait.classInfo;
|
|
}
|
|
} else {
|
|
for (var m = 0, n = mn.namespaces.length; m < n; m++) {
|
|
var qn = mn.getQName(m);
|
|
if (traitName === Multiname.getQualifiedName(qn)) {
|
|
return this.classInfoCache[qn] = trait.classInfo;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!this.base && this.vm.findDefiningAbc) {
|
|
var abc = this.vm.findDefiningAbc(mn);
|
|
if (abc !== null && !this.loadedAbcs[abc.name]) {
|
|
this.loadedAbcs[abc.name] = true;
|
|
this.loadAbc(abc);
|
|
return this.findClassInfo(mn);
|
|
}
|
|
}
|
|
return undefined;
|
|
};
|
|
ApplicationDomain.prototype.installNative = function (name, func) {
|
|
natives[name] = function () {
|
|
return func;
|
|
};
|
|
};
|
|
ApplicationDomain.prototype.findDefiningScript = function (mn, execute) {
|
|
var resolved = this.scriptCache[mn.runtimeId];
|
|
if (resolved && (resolved.script.executed || !execute)) {
|
|
return resolved;
|
|
}
|
|
if (this.base) {
|
|
resolved = this.base.findDefiningScript(mn, execute);
|
|
if (resolved) {
|
|
return resolved;
|
|
}
|
|
}
|
|
Counter.count('ApplicationDomain: findDefiningScript');
|
|
var abcs = this.abcs;
|
|
for (var i = 0; i < abcs.length; i++) {
|
|
var abc = abcs[i];
|
|
var scripts = abc.scripts;
|
|
for (var j = 0; j < scripts.length; j++) {
|
|
var script = scripts[j];
|
|
var traits = script.traits;
|
|
if (mn instanceof Multiname) {
|
|
for (var k = 0; k < traits.length; k++) {
|
|
var trait = traits[k];
|
|
if (mn.hasQName(trait.name)) {
|
|
if (execute) {
|
|
ensureScriptIsExecuted(script, String(trait.name));
|
|
}
|
|
return this.scriptCache[mn.runtimeId] = {
|
|
script: script,
|
|
trait: trait
|
|
};
|
|
}
|
|
}
|
|
} else {
|
|
Shumway.Debug.unexpected();
|
|
}
|
|
}
|
|
}
|
|
if (!this.base && this.vm.findDefiningAbc) {
|
|
var abc = this.vm.findDefiningAbc(mn);
|
|
if (abc !== null && !this.loadedAbcs[abc.name]) {
|
|
this.loadedAbcs[abc.name] = true;
|
|
this.loadAbc(abc);
|
|
return this.findDefiningScript(mn, execute);
|
|
}
|
|
}
|
|
return undefined;
|
|
};
|
|
ApplicationDomain.prototype.compileAbc = function (abc, writer) {
|
|
compileAbc(abc, writer);
|
|
};
|
|
ApplicationDomain.prototype.executeAbc = function (abc) {
|
|
this.loadAbc(abc);
|
|
executeScript(abc.lastScript);
|
|
};
|
|
ApplicationDomain.prototype.loadAbc = function (abc) {
|
|
if (Shumway.AVM2.Runtime.traceExecution.value) {
|
|
log('Loading: ' + abc.name);
|
|
}
|
|
abc.applicationDomain = this;
|
|
GlobalMultinameResolver.loadAbc(abc);
|
|
this.abcs.push(abc);
|
|
if (!this.base) {
|
|
Type.initializeTypes(this);
|
|
}
|
|
};
|
|
ApplicationDomain.prototype.broadcastMessage = function (type, message, origin) {
|
|
if (debug) {
|
|
Timer.start('broadcast: ' + type);
|
|
}
|
|
try {
|
|
this.onMessage.notify1(type, {
|
|
data: message,
|
|
origin: origin,
|
|
source: this
|
|
});
|
|
} catch (e) {
|
|
avm2.exceptions.push({
|
|
source: type,
|
|
message: e.message,
|
|
stack: e.stack
|
|
});
|
|
throw e;
|
|
}
|
|
if (debug) {
|
|
Timer.stop();
|
|
}
|
|
};
|
|
ApplicationDomain.prototype.traceLoadedClasses = function (lastOnly) {
|
|
var writer = new IndentingWriter();
|
|
lastOnly || writer.enter('Loaded Classes And Interfaces');
|
|
var classes = lastOnly ? [
|
|
this.loadedClasses.last()
|
|
] : this.loadedClasses;
|
|
classes.forEach(function (cls) {
|
|
if (cls !== Shumway.AVM2.Runtime.Class) {
|
|
cls.trace(writer);
|
|
}
|
|
});
|
|
lastOnly || writer.leave('');
|
|
};
|
|
return ApplicationDomain;
|
|
}();
|
|
Runtime.ApplicationDomain = ApplicationDomain;
|
|
var SecurityDomain = function () {
|
|
function SecurityDomain() {
|
|
this.compartment = createNewCompartment();
|
|
this.compartment.homePath = homePath;
|
|
this.compartment.release = true;
|
|
this.compartment.eval(snarf('compartment.js'));
|
|
}
|
|
SecurityDomain.prototype.initializeShell = function (sysMode, appMode) {
|
|
var compartment = this.compartment;
|
|
compartment.AVM2.initialize(sysMode, appMode);
|
|
compartment.AVM2.instance.systemDomain.executeAbc(compartment.grabAbc(homePath + 'src/avm2/generated/builtin/builtin.abc'));
|
|
compartment.AVM2.instance.systemDomain.executeAbc(compartment.grabAbc(homePath + 'src/avm2/generated/shell/shell.abc'));
|
|
this.systemDomain = compartment.AVM2.instance.systemDomain;
|
|
this.applicationDomain = compartment.AVM2.instance.applicationDomain;
|
|
};
|
|
return SecurityDomain;
|
|
}();
|
|
Runtime.SecurityDomain = SecurityDomain;
|
|
}(AVM2.Runtime || (AVM2.Runtime = {})));
|
|
var Runtime = AVM2.Runtime;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
var Glue = Shumway.AVM2.Runtime.Glue;
|
|
var ApplicationDomain = Shumway.AVM2.Runtime.ApplicationDomain;
|
|
var AVM2 = Shumway.AVM2.Runtime.AVM2;
|
|
var EXECUTION_MODE = Shumway.AVM2.Runtime.EXECUTION_MODE;
|
|
var ApplicationDomain = Shumway.AVM2.Runtime.ApplicationDomain;
|
|
var AVM2 = Shumway.AVM2.Runtime.AVM2;
|
|
var EXECUTION_MODE = Shumway.AVM2.Runtime.EXECUTION_MODE;
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
(function (Runtime) {
|
|
var Multiname = Shumway.AVM2.ABC.Multiname;
|
|
var Namespace = Shumway.AVM2.ABC.Namespace;
|
|
var ClassInfo = Shumway.AVM2.ABC.ClassInfo;
|
|
var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo;
|
|
var InstanceBindings = Shumway.AVM2.Runtime.InstanceBindings;
|
|
var ClassBindings = Shumway.AVM2.Runtime.ClassBindings;
|
|
var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter;
|
|
var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty;
|
|
var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty;
|
|
var defineNonEnumerableGetter = Shumway.ObjectUtilities.defineNonEnumerableGetter;
|
|
var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject;
|
|
var toKeyValueArray = Shumway.ObjectUtilities.toKeyValueArray;
|
|
var Interface = function () {
|
|
function Interface(classInfo) {
|
|
var ii = classInfo.instanceInfo;
|
|
true;
|
|
this.name = ii.name;
|
|
this.classInfo = classInfo;
|
|
}
|
|
Interface.createInterface = function (classInfo) {
|
|
var ii = classInfo.instanceInfo;
|
|
true;
|
|
if (Shumway.AVM2.Runtime.traceExecution.value) {
|
|
var str = 'Creating Interface ' + ii.name;
|
|
if (ii.interfaces.length) {
|
|
str += ' implements ' + ii.interfaces.map(function (name) {
|
|
return name.getName();
|
|
}).join(', ');
|
|
}
|
|
log(str);
|
|
}
|
|
var cls = new Interface(classInfo);
|
|
cls.interfaceBindings = new InstanceBindings(null, ii, null, null);
|
|
return cls;
|
|
};
|
|
Interface.prototype.toString = function () {
|
|
return '[interface ' + this.name + ']';
|
|
};
|
|
Interface.prototype.isInstance = function (value) {
|
|
if (value === null || typeof value !== 'object') {
|
|
return false;
|
|
}
|
|
true;
|
|
var qualifiedName = Multiname.getQualifiedName(this.name);
|
|
return value.class.implementedInterfaces[qualifiedName] !== undefined;
|
|
};
|
|
Interface.prototype.trace = function (writer) {
|
|
writer.enter('interface ' + this.name.getName());
|
|
writer.enter('interfaceBindings: ');
|
|
this.interfaceBindings.trace(writer);
|
|
writer.outdent();
|
|
writer.outdent();
|
|
writer.leave('}');
|
|
};
|
|
Interface.prototype.call = function (self, x) {
|
|
return x;
|
|
};
|
|
Interface.prototype.apply = function (self, args) {
|
|
return args[0];
|
|
};
|
|
return Interface;
|
|
}();
|
|
Runtime.Interface = Interface;
|
|
function setDefaultProperties(cls) {
|
|
defineNonEnumerableProperty(cls.dynamicPrototype, Multiname.getPublicQualifiedName('constructor'), cls);
|
|
defineReadOnlyProperty(cls.traitsPrototype, 'class', cls);
|
|
defineReadOnlyProperty(cls.instanceConstructor, 'class', cls);
|
|
}
|
|
Runtime.setDefaultProperties = setDefaultProperties;
|
|
var Class = function () {
|
|
function Class(name, instanceConstructor, callable) {
|
|
this.debugName = name;
|
|
if (instanceConstructor) {
|
|
true;
|
|
this.instanceConstructor = instanceConstructor;
|
|
this.instanceConstructorNoInitialize = instanceConstructor;
|
|
this.hasInitialize = 0;
|
|
this.instanceConstructor.class = this;
|
|
}
|
|
if (!callable) {
|
|
callable = Shumway.AVM2.Runtime.ApplicationDomain.coerceCallable(this);
|
|
} else if (callable === Shumway.AVM2.Runtime.ApplicationDomain.coerceCallable) {
|
|
callable = Shumway.AVM2.Runtime.ApplicationDomain.coerceCallable(this);
|
|
}
|
|
defineNonEnumerableProperty(this, 'call', callable.call);
|
|
defineNonEnumerableProperty(this, 'apply', callable.apply);
|
|
}
|
|
Class.createClass = function (classInfo, baseClass, scope) {
|
|
var ci = classInfo;
|
|
var ii = ci.instanceInfo;
|
|
var domain = ci.abc.applicationDomain;
|
|
var className = Multiname.getName(ii.name);
|
|
var isNativeClass = ci.native;
|
|
if (isNativeClass) {
|
|
var buildClass = getNative(ci.native.cls);
|
|
if (!buildClass) {
|
|
Shumway.Debug.unexpected('No native for ' + ci.native.cls);
|
|
}
|
|
if (!baseClass) {
|
|
scope = new Scope(scope, Class);
|
|
}
|
|
}
|
|
var classScope = new Scope(scope, null);
|
|
var instanceConstructor = createFunction(ii.init, classScope, false);
|
|
var cls;
|
|
if (isNativeClass) {
|
|
cls = buildClass(domain, classScope, instanceConstructor, baseClass);
|
|
} else {
|
|
cls = new Class(className, instanceConstructor);
|
|
}
|
|
cls.className = className;
|
|
cls.classInfo = classInfo;
|
|
cls.scope = classScope;
|
|
classScope.object = cls;
|
|
var classNatives;
|
|
var instanceNatives;
|
|
if (isNativeClass) {
|
|
if (cls.native) {
|
|
classNatives = cls.native.static;
|
|
instanceNatives = cls.native.instance;
|
|
}
|
|
} else {
|
|
cls.extend(baseClass);
|
|
}
|
|
cls.classBindings = new ClassBindings(classInfo, classScope, classNatives);
|
|
cls.classBindings.applyTo(domain, cls);
|
|
defineReadOnlyProperty(cls, Shumway.AVM2.Runtime.VM_IS_CLASS, true);
|
|
cls.instanceBindings = new InstanceBindings(baseClass ? baseClass.instanceBindings : null, ii, classScope, instanceNatives);
|
|
if (cls.instanceConstructor) {
|
|
cls.instanceBindings.applyTo(domain, cls.traitsPrototype);
|
|
}
|
|
cls.implementedInterfaces = cls.instanceBindings.implementedInterfaces;
|
|
return cls;
|
|
};
|
|
Class.prototype.setSymbol = function (props) {
|
|
this.instanceConstructor.prototype.symbol = props;
|
|
};
|
|
Class.prototype.getSymbol = function () {
|
|
return this.instanceConstructor.prototype.symbol;
|
|
};
|
|
Class.prototype.initializeInstance = function (obj) {
|
|
var c = this;
|
|
var initializes = [];
|
|
while (c) {
|
|
if (c.hasInitialize & Class.OWN_INITIALIZE) {
|
|
initializes.push(c.instanceConstructor.prototype.initialize);
|
|
}
|
|
c = c.baseClass;
|
|
}
|
|
var s;
|
|
while (s = initializes.pop()) {
|
|
s.call(obj);
|
|
}
|
|
Counter.count('Initialize Instance ' + obj.class);
|
|
};
|
|
Class.prototype.createInstance = function (args) {
|
|
var o = Object.create(this.instanceConstructor.prototype);
|
|
this.instanceConstructor.apply(o, args);
|
|
return o;
|
|
};
|
|
Class.prototype.createAsSymbol = function (props) {
|
|
var o = Object.create(this.instanceConstructor.prototype);
|
|
if (o.symbol) {
|
|
var symbol = Object.create(o.symbol);
|
|
for (var prop in props) {
|
|
symbol[prop] = props[prop];
|
|
}
|
|
o.symbol = symbol;
|
|
} else {
|
|
o.symbol = props;
|
|
}
|
|
return o;
|
|
};
|
|
Class.prototype.extendNative = function (baseClass, native) {
|
|
this.baseClass = baseClass;
|
|
this.dynamicPrototype = Object.getPrototypeOf(native.prototype);
|
|
this.instanceConstructor.prototype = this.traitsPrototype = native.prototype;
|
|
setDefaultProperties(this);
|
|
};
|
|
Class.prototype.extendWrapper = function (baseClass, wrapper) {
|
|
true;
|
|
this.baseClass = baseClass;
|
|
this.dynamicPrototype = Object.create(baseClass.dynamicPrototype);
|
|
var traitsPrototype = Object.create(this.dynamicPrototype, Shumway.ObjectUtilities.getOwnPropertyDescriptors(wrapper.prototype));
|
|
this.instanceConstructor.prototype = this.traitsPrototype = traitsPrototype;
|
|
setDefaultProperties(this);
|
|
};
|
|
Class.prototype.extendBuiltin = function (baseClass) {
|
|
true;
|
|
this.baseClass = baseClass;
|
|
this.dynamicPrototype = this.traitsPrototype = this.instanceConstructor.prototype;
|
|
setDefaultProperties(this);
|
|
};
|
|
Class.prototype.extend = function (baseClass) {
|
|
true;
|
|
this.baseClass = baseClass;
|
|
this.dynamicPrototype = Object.create(baseClass.dynamicPrototype);
|
|
if (baseClass.hasInitialize) {
|
|
var instanceConstructorNoInitialize = this.instanceConstructor;
|
|
var self = this;
|
|
this.instanceConstructor = function () {
|
|
self.initializeInstance(this);
|
|
instanceConstructorNoInitialize.apply(this, arguments);
|
|
};
|
|
defineReadOnlyProperty(this.instanceConstructor, 'class', instanceConstructorNoInitialize.class);
|
|
this.hasInitialize |= Class.SUPER_INITIALIZE;
|
|
}
|
|
this.instanceConstructor.prototype = this.traitsPrototype = Object.create(this.dynamicPrototype);
|
|
setDefaultProperties(this);
|
|
};
|
|
Class.prototype.setDefaultProperties = function () {
|
|
setDefaultProperties(this);
|
|
};
|
|
Class.prototype.link = function (definition) {
|
|
true;
|
|
true;
|
|
if (definition.initialize) {
|
|
if (!this.hasInitialize) {
|
|
var instanceConstructorNoInitialize = this.instanceConstructor;
|
|
var self = this;
|
|
this.instanceConstructor = function () {
|
|
self.initializeInstance(this);
|
|
instanceConstructorNoInitialize.apply(this, arguments);
|
|
};
|
|
defineReadOnlyProperty(this.instanceConstructor, 'class', instanceConstructorNoInitialize.class);
|
|
this.instanceConstructor.prototype = instanceConstructorNoInitialize.prototype;
|
|
}
|
|
this.hasInitialize |= Class.OWN_INITIALIZE;
|
|
}
|
|
var dynamicPrototype = this.dynamicPrototype;
|
|
var keys = Object.keys(definition);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var propertyName = keys[i];
|
|
Object.defineProperty(dynamicPrototype, propertyName, Object.getOwnPropertyDescriptor(definition, propertyName));
|
|
}
|
|
function glueProperties(obj, properties) {
|
|
var keys = Object.keys(properties);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var propertyName = keys[i];
|
|
var propertyGlue = properties[propertyName];
|
|
var propertySimpleName;
|
|
var glueOpenMethod = false;
|
|
if (propertyGlue.indexOf('open ') >= 0) {
|
|
propertySimpleName = propertyGlue.substring(5);
|
|
glueOpenMethod = true;
|
|
} else {
|
|
propertySimpleName = propertyGlue;
|
|
}
|
|
true;
|
|
var qn = Multiname.getQualifiedName(Multiname.fromSimpleName(propertySimpleName));
|
|
if (glueOpenMethod) {
|
|
qn = Shumway.AVM2.Runtime.VM_OPEN_METHOD_PREFIX + qn;
|
|
}
|
|
true;
|
|
var descriptor = Object.getOwnPropertyDescriptor(obj, qn);
|
|
if (descriptor && descriptor.get) {
|
|
Object.defineProperty(obj, propertyName, descriptor);
|
|
} else {
|
|
Object.defineProperty(obj, propertyName, {
|
|
get: new Function('', 'return this.' + qn),
|
|
set: new Function('v', 'this.' + qn + ' = v')
|
|
});
|
|
}
|
|
}
|
|
}
|
|
function generatePropertiesFromTraits(traits) {
|
|
var properties = createEmptyObject();
|
|
traits.forEach(function (trait) {
|
|
var ns = trait.name.getNamespace();
|
|
if (!ns.isPublic()) {
|
|
return;
|
|
}
|
|
properties[trait.name.getName()] = (trait.isMethod() ? 'open ' : '') + 'public ' + trait.name.getName();
|
|
});
|
|
return properties;
|
|
}
|
|
var glue = definition.__glue__;
|
|
if (!glue) {
|
|
return;
|
|
}
|
|
if (glue.script) {
|
|
if (glue.script.instance) {
|
|
if (Shumway.isNumber(glue.script.instance)) {
|
|
true;
|
|
glueProperties(dynamicPrototype, generatePropertiesFromTraits(this.classInfo.instanceInfo.traits));
|
|
} else {
|
|
glueProperties(dynamicPrototype, glue.script.instance);
|
|
}
|
|
}
|
|
if (glue.script.static) {
|
|
if (Shumway.isNumber(glue.script.static)) {
|
|
true;
|
|
glueProperties(this, generatePropertiesFromTraits(this.classInfo.traits));
|
|
} else {
|
|
glueProperties(this, glue.script.static);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
Class.prototype.linkNatives = function (definition) {
|
|
var glue = definition.__glue__;
|
|
this.native = glue.native;
|
|
};
|
|
Class.prototype.verify = function () {
|
|
var instanceConstructor = this.instanceConstructor;
|
|
var tP = this.traitsPrototype;
|
|
var dP = this.dynamicPrototype;
|
|
true;
|
|
true;
|
|
true;
|
|
true;
|
|
if (tP !== Object.prototype) {
|
|
}
|
|
true;
|
|
};
|
|
Class.prototype.coerce = function (value) {
|
|
return value;
|
|
};
|
|
Class.prototype.isInstanceOf = function (value) {
|
|
return this.isInstance(value);
|
|
};
|
|
Class.prototype.isInstance = function (value) {
|
|
if (value === null || typeof value !== 'object') {
|
|
return false;
|
|
}
|
|
return this.dynamicPrototype.isPrototypeOf(value);
|
|
};
|
|
Class.prototype.trace = function (writer) {
|
|
var description = this.debugName + (this.baseClass ? ' extends ' + this.baseClass.debugName : '');
|
|
writer.enter('class ' + description + ' {');
|
|
writer.writeLn('scope: ' + this.scope);
|
|
writer.writeLn('baseClass: ' + this.baseClass);
|
|
writer.writeLn('classInfo: ' + this.classInfo);
|
|
writer.writeLn('dynamicPrototype: ' + this.dynamicPrototype);
|
|
writer.writeLn('traitsPrototype: ' + this.traitsPrototype);
|
|
writer.writeLn('dynamicPrototype === traitsPrototype: ' + (this.dynamicPrototype === this.traitsPrototype));
|
|
writer.writeLn('instanceConstructor: ' + this.instanceConstructor);
|
|
writer.writeLn('instanceConstructorNoInitialize: ' + this.instanceConstructorNoInitialize);
|
|
writer.writeLn('instanceConstructor === instanceConstructorNoInitialize: ' + (this.instanceConstructor === this.instanceConstructorNoInitialize));
|
|
var traitsPrototype = this.traitsPrototype;
|
|
writer.enter('traitsPrototype: ');
|
|
if (traitsPrototype) {
|
|
writer.enter('VM_SLOTS: ');
|
|
writer.writeArray(traitsPrototype.asSlots.byID.map(function (slot) {
|
|
return slot.trait;
|
|
}));
|
|
writer.outdent();
|
|
writer.enter('VM_BINDINGS: ');
|
|
writer.writeArray(traitsPrototype.asBindings.map(function (binding) {
|
|
var pd = Object.getOwnPropertyDescriptor(traitsPrototype, binding);
|
|
var str = binding;
|
|
if (pd.get || pd.set) {
|
|
if (pd.get) {
|
|
str += ' getter: ' + debugName(pd.get);
|
|
}
|
|
if (pd.set) {
|
|
str += ' setter: ' + debugName(pd.set);
|
|
}
|
|
} else {
|
|
str += ' value: ' + debugName(pd.value);
|
|
}
|
|
return str;
|
|
}));
|
|
writer.outdent();
|
|
writer.enter('VM_OPEN_METHODS: ');
|
|
writer.writeArray(toKeyValueArray(traitsPrototype.asOpenMethods).map(function (pair) {
|
|
return pair[0] + ': ' + debugName(pair[1]);
|
|
}));
|
|
writer.outdent();
|
|
}
|
|
writer.enter('classBindings: ');
|
|
this.classBindings.trace(writer);
|
|
writer.outdent();
|
|
writer.enter('instanceBindings: ');
|
|
this.instanceBindings.trace(writer);
|
|
writer.outdent();
|
|
writer.outdent();
|
|
writer.writeLn('call: ' + this.call);
|
|
writer.writeLn('apply: ' + this.apply);
|
|
writer.leave('}');
|
|
};
|
|
Class.prototype.toString = function () {
|
|
return '[class ' + this.classInfo.instanceInfo.name.name + ']';
|
|
};
|
|
Class.OWN_INITIALIZE = 1;
|
|
Class.SUPER_INITIALIZE = 2;
|
|
return Class;
|
|
}();
|
|
Runtime.Class = Class;
|
|
var callable = Shumway.AVM2.Runtime.ApplicationDomain.coerceCallable(Class);
|
|
defineNonEnumerableProperty(Class, 'call', callable.call);
|
|
defineNonEnumerableProperty(Class, 'apply', callable.apply);
|
|
Class.instanceConstructor = Class;
|
|
Class.toString = Class.prototype.toString;
|
|
Class.native = {
|
|
instance: {
|
|
prototype: {
|
|
get: function () {
|
|
return this.dynamicPrototype;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}(AVM2.Runtime || (AVM2.Runtime = {})));
|
|
var Runtime = AVM2.Runtime;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
var Interface = Shumway.AVM2.Runtime.Interface;
|
|
var Class = Shumway.AVM2.Runtime.Class;
|
|
var Binding = Shumway.AVM2.Runtime.Binding;
|
|
var Bindings = Shumway.AVM2.Runtime.Bindings;
|
|
var ActivationBindings = Shumway.AVM2.Runtime.ActivationBindings;
|
|
var CatchBindings = Shumway.AVM2.Runtime.CatchBindings;
|
|
var ScriptBindings = Shumway.AVM2.Runtime.ScriptBindings;
|
|
var ClassBindings = Shumway.AVM2.Runtime.ClassBindings;
|
|
var InstanceBindings = Shumway.AVM2.Runtime.InstanceBindings;
|
|
var Interface = Shumway.AVM2.Runtime.Interface;
|
|
var Class = Shumway.AVM2.Runtime.Class;
|
|
var XRegExp = function (undefined) {
|
|
var REGEX_DATA = 'xregexp', self, features = {
|
|
astral: false,
|
|
natives: false
|
|
}, nativ = {
|
|
exec: RegExp.prototype.exec,
|
|
test: RegExp.prototype.test,
|
|
match: String.prototype.match,
|
|
replace: String.prototype.replace,
|
|
split: String.prototype.split
|
|
}, fixed = {}, cache = {}, patternCache = {}, tokens = [], defaultScope = 'default', classScope = 'class', nativeTokens = {
|
|
'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]/,
|
|
'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]/
|
|
}, replacementToken = /\$(?:{([\w$]+)}|([\d$&`']))/g, correctExecNpcg = nativ.exec.call(/()??/, '')[1] === undefined, hasNativeY = RegExp.prototype.sticky !== undefined, registeredFlags = {
|
|
g: true,
|
|
i: true,
|
|
m: true,
|
|
y: hasNativeY
|
|
}, toString = {}.toString, add;
|
|
function augment(regex, captureNames, addProto) {
|
|
var p;
|
|
if (addProto) {
|
|
if (regex.__proto__) {
|
|
regex.__proto__ = self.prototype;
|
|
} else {
|
|
for (p in self.prototype) {
|
|
regex[p] = self.prototype[p];
|
|
}
|
|
}
|
|
}
|
|
regex[REGEX_DATA] = {
|
|
captureNames: captureNames
|
|
};
|
|
return regex;
|
|
}
|
|
function clipDuplicates(str) {
|
|
return nativ.replace.call(str, /([\s\S])(?=[\s\S]*\1)/g, '');
|
|
}
|
|
function copy(regex, options) {
|
|
if (!self.isRegExp(regex)) {
|
|
throw new TypeError('Type RegExp expected');
|
|
}
|
|
var flags = nativ.exec.call(/\/([a-z]*)$/i, String(regex))[1];
|
|
options = options || {};
|
|
if (options.add) {
|
|
flags = clipDuplicates(flags + options.add);
|
|
}
|
|
if (options.remove) {
|
|
flags = nativ.replace.call(flags, new RegExp('[' + options.remove + ']+', 'g'), '');
|
|
}
|
|
regex = augment(new RegExp(regex.source, flags), hasNamedCapture(regex) ? regex[REGEX_DATA].captureNames.slice(0) : null, options.addProto);
|
|
return regex;
|
|
}
|
|
function getBaseProps() {
|
|
return {
|
|
captureNames: null
|
|
};
|
|
}
|
|
function hasNamedCapture(regex) {
|
|
return !(!(regex[REGEX_DATA] && regex[REGEX_DATA].captureNames));
|
|
}
|
|
function indexOf(array, value) {
|
|
if (Array.prototype.indexOf) {
|
|
return array.indexOf(value);
|
|
}
|
|
var len = array.length, i;
|
|
for (i = 0; i < len; ++i) {
|
|
if (array[i] === value) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
function isType(value, type) {
|
|
return toString.call(value) === '[object ' + type + ']';
|
|
}
|
|
function isQuantifierNext(pattern, pos, flags) {
|
|
return nativ.test.call(flags.indexOf('x') > -1 ? /^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/ : /^(?:\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/, pattern.slice(pos));
|
|
}
|
|
function prepareFlags(pattern, flags) {
|
|
var i;
|
|
if (clipDuplicates(flags) !== flags) {
|
|
throw new SyntaxError('Invalid duplicate regex flag ' + flags);
|
|
}
|
|
pattern = nativ.replace.call(pattern, /^\(\?([\w$]+)\)/, function ($0, $1) {
|
|
if (nativ.test.call(/[gy]/, $1)) {
|
|
throw new SyntaxError('Cannot use flag g or y in mode modifier ' + $0);
|
|
}
|
|
flags = clipDuplicates(flags + $1);
|
|
return '';
|
|
});
|
|
for (i = 0; i < flags.length; ++i) {
|
|
if (!registeredFlags[flags.charAt(i)]) {
|
|
throw new SyntaxError('Unknown regex flag ' + flags.charAt(i));
|
|
}
|
|
}
|
|
return {
|
|
pattern: pattern,
|
|
flags: flags
|
|
};
|
|
}
|
|
function prepareOptions(value) {
|
|
value = value || {};
|
|
if (isType(value, 'String')) {
|
|
value = self.forEach(value, /[^\s,]+/, function (match) {
|
|
this[match] = true;
|
|
}, {});
|
|
}
|
|
return value;
|
|
}
|
|
function registerFlag(flag) {
|
|
if (!/^[\w$]$/.test(flag)) {
|
|
throw new Error('Flag must be a single character A-Za-z0-9_$');
|
|
}
|
|
registeredFlags[flag] = true;
|
|
}
|
|
function runTokens(pattern, flags, pos, scope, context) {
|
|
var i = tokens.length, result = null, match, t;
|
|
while (i--) {
|
|
t = tokens[i];
|
|
if ((t.scope === scope || t.scope === 'all') && (!t.flag || flags.indexOf(t.flag) > -1)) {
|
|
match = self.exec(pattern, t.regex, pos, 'sticky');
|
|
if (match) {
|
|
result = {
|
|
matchLength: match[0].length,
|
|
output: t.handler.call(context, match, scope, flags),
|
|
reparse: t.reparse
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function setAstral(on) {
|
|
self.cache.flush('patterns');
|
|
features.astral = on;
|
|
}
|
|
function setNatives(on) {
|
|
RegExp.prototype.exec = (on ? fixed : nativ).exec;
|
|
RegExp.prototype.test = (on ? fixed : nativ).test;
|
|
String.prototype.match = (on ? fixed : nativ).match;
|
|
String.prototype.replace = (on ? fixed : nativ).replace;
|
|
String.prototype.split = (on ? fixed : nativ).split;
|
|
features.natives = on;
|
|
}
|
|
function toObject(value) {
|
|
if (value == null) {
|
|
throw new TypeError('Cannot convert null or undefined to object');
|
|
}
|
|
return value;
|
|
}
|
|
self = function (pattern, flags) {
|
|
var context = {
|
|
hasNamedCapture: false,
|
|
captureNames: []
|
|
}, scope = defaultScope, output = '', pos = 0, result, token, key;
|
|
if (self.isRegExp(pattern)) {
|
|
if (flags !== undefined) {
|
|
throw new TypeError('Cannot supply flags when copying a RegExp');
|
|
}
|
|
return copy(pattern, {
|
|
addProto: true
|
|
});
|
|
}
|
|
pattern = pattern === undefined ? '' : String(pattern);
|
|
flags = flags === undefined ? '' : String(flags);
|
|
key = pattern + '***' + flags;
|
|
if (!patternCache[key]) {
|
|
result = prepareFlags(pattern, flags);
|
|
pattern = result.pattern;
|
|
flags = result.flags;
|
|
while (pos < pattern.length) {
|
|
do {
|
|
result = runTokens(pattern, flags, pos, scope, context);
|
|
if (result && result.reparse) {
|
|
pattern = pattern.slice(0, pos) + result.output + pattern.slice(pos + result.matchLength);
|
|
}
|
|
} while (result && result.reparse);
|
|
if (result) {
|
|
output += result.output;
|
|
pos += result.matchLength || 1;
|
|
} else {
|
|
token = self.exec(pattern, nativeTokens[scope], pos, 'sticky')[0];
|
|
output += token;
|
|
pos += token.length;
|
|
if (token === '[' && scope === defaultScope) {
|
|
scope = classScope;
|
|
} else if (token === ']' && scope === classScope) {
|
|
scope = defaultScope;
|
|
}
|
|
}
|
|
}
|
|
patternCache[key] = {
|
|
pattern: nativ.replace.call(output, /\(\?:\)(?=\(\?:\))|^\(\?:\)|\(\?:\)$/g, ''),
|
|
flags: nativ.replace.call(flags, /[^gimy]+/g, ''),
|
|
captures: context.hasNamedCapture ? context.captureNames : null
|
|
};
|
|
}
|
|
key = patternCache[key];
|
|
return augment(new RegExp(key.pattern, key.flags), key.captures, true);
|
|
};
|
|
self.prototype = new RegExp();
|
|
self.version = '3.0.0-pre';
|
|
self.addToken = function (regex, handler, options) {
|
|
options = options || {};
|
|
var optionalFlags = options.optionalFlags, i;
|
|
if (options.flag) {
|
|
registerFlag(options.flag);
|
|
}
|
|
if (optionalFlags) {
|
|
optionalFlags = nativ.split.call(optionalFlags, '');
|
|
for (i = 0; i < optionalFlags.length; ++i) {
|
|
registerFlag(optionalFlags[i]);
|
|
}
|
|
}
|
|
tokens.push({
|
|
regex: copy(regex, {
|
|
add: 'g' + (hasNativeY ? 'y' : '')
|
|
}),
|
|
handler: handler,
|
|
scope: options.scope || defaultScope,
|
|
flag: options.flag,
|
|
reparse: options.reparse
|
|
});
|
|
self.cache.flush('patterns');
|
|
};
|
|
self.cache = function (pattern, flags) {
|
|
var key = pattern + '***' + (flags || '');
|
|
return cache[key] || (cache[key] = self(pattern, flags));
|
|
};
|
|
self.cache.flush = function (cacheName) {
|
|
if (cacheName === 'patterns') {
|
|
patternCache = {};
|
|
} else {
|
|
cache = {};
|
|
}
|
|
};
|
|
self.escape = function (str) {
|
|
return nativ.replace.call(toObject(str), /[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
};
|
|
self.exec = function (str, regex, pos, sticky) {
|
|
var cacheFlags = 'g', match, r2;
|
|
if (hasNativeY && (sticky || regex.sticky && sticky !== false)) {
|
|
cacheFlags += 'y';
|
|
}
|
|
regex[REGEX_DATA] = regex[REGEX_DATA] || getBaseProps();
|
|
r2 = regex[REGEX_DATA][cacheFlags] || (regex[REGEX_DATA][cacheFlags] = copy(regex, {
|
|
add: cacheFlags,
|
|
remove: sticky === false ? 'y' : ''
|
|
}));
|
|
r2.lastIndex = pos = pos || 0;
|
|
match = fixed.exec.call(r2, str);
|
|
if (sticky && match && match.index !== pos) {
|
|
match = null;
|
|
}
|
|
if (regex.global) {
|
|
regex.lastIndex = match ? r2.lastIndex : 0;
|
|
}
|
|
return match;
|
|
};
|
|
self.forEach = function (str, regex, callback, context) {
|
|
var pos = 0, i = -1, match;
|
|
while (match = self.exec(str, regex, pos)) {
|
|
callback.call(context, match, ++i, str, regex);
|
|
pos = match.index + (match[0].length || 1);
|
|
}
|
|
return context;
|
|
};
|
|
self.globalize = function (regex) {
|
|
return copy(regex, {
|
|
add: 'g',
|
|
addProto: true
|
|
});
|
|
};
|
|
self.install = function (options) {
|
|
options = prepareOptions(options);
|
|
if (!features.astral && options.astral) {
|
|
setAstral(true);
|
|
}
|
|
if (!features.natives && options.natives) {
|
|
setNatives(true);
|
|
}
|
|
};
|
|
self.isInstalled = function (feature) {
|
|
return !(!features[feature]);
|
|
};
|
|
self.isRegExp = function (value) {
|
|
return toString.call(value) === '[object RegExp]';
|
|
};
|
|
self.match = function (str, regex, scope) {
|
|
var global = regex.global && scope !== 'one' || scope === 'all', cacheFlags = (global ? 'g' : '') + (regex.sticky ? 'y' : ''), result, r2;
|
|
regex[REGEX_DATA] = regex[REGEX_DATA] || getBaseProps();
|
|
r2 = regex[REGEX_DATA][cacheFlags || 'noGY'] || (regex[REGEX_DATA][cacheFlags || 'noGY'] = copy(regex, {
|
|
add: cacheFlags,
|
|
remove: scope === 'one' ? 'g' : ''
|
|
}));
|
|
result = nativ.match.call(toObject(str), r2);
|
|
if (regex.global) {
|
|
regex.lastIndex = scope === 'one' && result ? result.index + result[0].length : 0;
|
|
}
|
|
return global ? result || [] : result && result[0];
|
|
};
|
|
self.matchChain = function (str, chain) {
|
|
return function recurseChain(values, level) {
|
|
var item = chain[level].regex ? chain[level] : {
|
|
regex: chain[level]
|
|
}, matches = [], addMatch = function (match) {
|
|
if (item.backref) {
|
|
if (!(match.hasOwnProperty(item.backref) || +item.backref < match.length)) {
|
|
throw new ReferenceError('Backreference to undefined group: ' + item.backref);
|
|
}
|
|
matches.push(match[item.backref] || '');
|
|
} else {
|
|
matches.push(match[0]);
|
|
}
|
|
}, i;
|
|
for (i = 0; i < values.length; ++i) {
|
|
self.forEach(values[i], item.regex, addMatch);
|
|
}
|
|
return level === chain.length - 1 || !matches.length ? matches : recurseChain(matches, level + 1);
|
|
}([
|
|
str
|
|
], 0);
|
|
};
|
|
self.replace = function (str, search, replacement, scope) {
|
|
var isRegex = self.isRegExp(search), global = search.global && scope !== 'one' || scope === 'all', cacheFlags = (global ? 'g' : '') + (search.sticky ? 'y' : ''), s2 = search, result;
|
|
if (isRegex) {
|
|
search[REGEX_DATA] = search[REGEX_DATA] || getBaseProps();
|
|
s2 = search[REGEX_DATA][cacheFlags || 'noGY'] || (search[REGEX_DATA][cacheFlags || 'noGY'] = copy(search, {
|
|
add: cacheFlags,
|
|
remove: scope === 'one' ? 'g' : ''
|
|
}));
|
|
} else if (global) {
|
|
s2 = new RegExp(self.escape(String(search)), 'g');
|
|
}
|
|
result = fixed.replace.call(toObject(str), s2, replacement);
|
|
if (isRegex && search.global) {
|
|
search.lastIndex = 0;
|
|
}
|
|
return result;
|
|
};
|
|
self.replaceEach = function (str, replacements) {
|
|
var i, r;
|
|
for (i = 0; i < replacements.length; ++i) {
|
|
r = replacements[i];
|
|
str = self.replace(str, r[0], r[1], r[2]);
|
|
}
|
|
return str;
|
|
};
|
|
self.split = function (str, separator, limit) {
|
|
return fixed.split.call(toObject(str), separator, limit);
|
|
};
|
|
self.test = function (str, regex, pos, sticky) {
|
|
return !(!self.exec(str, regex, pos, sticky));
|
|
};
|
|
self.uninstall = function (options) {
|
|
options = prepareOptions(options);
|
|
if (features.astral && options.astral) {
|
|
setAstral(false);
|
|
}
|
|
if (features.natives && options.natives) {
|
|
setNatives(false);
|
|
}
|
|
};
|
|
self.union = function (patterns, flags) {
|
|
var parts = /(\()(?!\?)|\\([1-9]\d*)|\\[\s\S]|\[(?:[^\\\]]|\\[\s\S])*]/g, output = [], numCaptures = 0, numPriorCaptures, captureNames, pattern, rewrite = function (match, paren, backref) {
|
|
var name = captureNames[numCaptures - numPriorCaptures];
|
|
if (paren) {
|
|
++numCaptures;
|
|
if (name) {
|
|
return '(?<' + name + '>';
|
|
}
|
|
} else if (backref) {
|
|
return '\\' + (+backref + numPriorCaptures);
|
|
}
|
|
return match;
|
|
}, i;
|
|
if (!(isType(patterns, 'Array') && patterns.length)) {
|
|
throw new TypeError('Must provide a nonempty array of patterns to merge');
|
|
}
|
|
for (i = 0; i < patterns.length; ++i) {
|
|
pattern = patterns[i];
|
|
if (self.isRegExp(pattern)) {
|
|
numPriorCaptures = numCaptures;
|
|
captureNames = pattern[REGEX_DATA] && pattern[REGEX_DATA].captureNames || [];
|
|
output.push(nativ.replace.call(self(pattern.source).source, parts, rewrite));
|
|
} else {
|
|
output.push(self.escape(pattern));
|
|
}
|
|
}
|
|
return self(output.join('|'), flags);
|
|
};
|
|
fixed.exec = function (str) {
|
|
var origLastIndex = this.lastIndex, match = nativ.exec.apply(this, arguments), name, r2, i;
|
|
if (match) {
|
|
if (!correctExecNpcg && match.length > 1 && indexOf(match, '') > -1) {
|
|
r2 = copy(this, {
|
|
remove: 'g'
|
|
});
|
|
nativ.replace.call(String(str).slice(match.index), r2, function () {
|
|
var len = arguments.length, i;
|
|
for (i = 1; i < len - 2; ++i) {
|
|
if (arguments[i] === undefined) {
|
|
match[i] = undefined;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
if (this[REGEX_DATA] && this[REGEX_DATA].captureNames) {
|
|
for (i = 1; i < match.length; ++i) {
|
|
name = this[REGEX_DATA].captureNames[i - 1];
|
|
if (name) {
|
|
match[name] = match[i];
|
|
}
|
|
}
|
|
}
|
|
if (this.global && !match[0].length && this.lastIndex > match.index) {
|
|
this.lastIndex = match.index;
|
|
}
|
|
}
|
|
if (!this.global) {
|
|
this.lastIndex = origLastIndex;
|
|
}
|
|
return match;
|
|
};
|
|
fixed.test = function (str) {
|
|
return !(!fixed.exec.call(this, str));
|
|
};
|
|
fixed.match = function (regex) {
|
|
var result;
|
|
if (!self.isRegExp(regex)) {
|
|
regex = new RegExp(regex);
|
|
} else if (regex.global) {
|
|
result = nativ.match.apply(this, arguments);
|
|
regex.lastIndex = 0;
|
|
return result;
|
|
}
|
|
return fixed.exec.call(regex, toObject(this));
|
|
};
|
|
fixed.replace = function (search, replacement) {
|
|
var isRegex = self.isRegExp(search), origLastIndex, captureNames, result;
|
|
if (isRegex) {
|
|
if (search[REGEX_DATA]) {
|
|
captureNames = search[REGEX_DATA].captureNames;
|
|
}
|
|
origLastIndex = search.lastIndex;
|
|
} else {
|
|
search += '';
|
|
}
|
|
if (isType(replacement, 'Function')) {
|
|
result = nativ.replace.call(String(this), search, function () {
|
|
var args = arguments, i;
|
|
if (captureNames) {
|
|
args[0] = new String(args[0]);
|
|
for (i = 0; i < captureNames.length; ++i) {
|
|
if (captureNames[i]) {
|
|
args[0][captureNames[i]] = args[i + 1];
|
|
}
|
|
}
|
|
}
|
|
if (isRegex && search.global) {
|
|
search.lastIndex = args[args.length - 2] + args[0].length;
|
|
}
|
|
return replacement.apply(undefined, args);
|
|
});
|
|
} else {
|
|
result = nativ.replace.call(this == null ? this : String(this), search, function () {
|
|
var args = arguments;
|
|
return nativ.replace.call(String(replacement), replacementToken, function ($0, $1, $2) {
|
|
var n;
|
|
if ($1) {
|
|
n = +$1;
|
|
if (n <= args.length - 3) {
|
|
return args[n] || '';
|
|
}
|
|
n = captureNames ? indexOf(captureNames, $1) : -1;
|
|
if (n < 0) {
|
|
throw new SyntaxError('Backreference to undefined group ' + $0);
|
|
}
|
|
return args[n + 1] || '';
|
|
}
|
|
if ($2 === '$') {
|
|
return '$';
|
|
}
|
|
if ($2 === '&' || +$2 === 0) {
|
|
return args[0];
|
|
}
|
|
if ($2 === '`') {
|
|
return args[args.length - 1].slice(0, args[args.length - 2]);
|
|
}
|
|
if ($2 === '\'') {
|
|
return args[args.length - 1].slice(args[args.length - 2] + args[0].length);
|
|
}
|
|
$2 = +$2;
|
|
if (!isNaN($2)) {
|
|
if ($2 > args.length - 3) {
|
|
throw new SyntaxError('Backreference to undefined group ' + $0);
|
|
}
|
|
return args[$2] || '';
|
|
}
|
|
throw new SyntaxError('Invalid token ' + $0);
|
|
});
|
|
});
|
|
}
|
|
if (isRegex) {
|
|
if (search.global) {
|
|
search.lastIndex = 0;
|
|
} else {
|
|
search.lastIndex = origLastIndex;
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
fixed.split = function (separator, limit) {
|
|
if (!self.isRegExp(separator)) {
|
|
return nativ.split.apply(this, arguments);
|
|
}
|
|
var str = String(this), output = [], origLastIndex = separator.lastIndex, lastLastIndex = 0, lastLength;
|
|
limit = (limit === undefined ? -1 : limit) >>> 0;
|
|
self.forEach(str, separator, function (match) {
|
|
if (match.index + match[0].length > lastLastIndex) {
|
|
output.push(str.slice(lastLastIndex, match.index));
|
|
if (match.length > 1 && match.index < str.length) {
|
|
Array.prototype.push.apply(output, match.slice(1));
|
|
}
|
|
lastLength = match[0].length;
|
|
lastLastIndex = match.index + lastLength;
|
|
}
|
|
});
|
|
if (lastLastIndex === str.length) {
|
|
if (!nativ.test.call(separator, '') || lastLength) {
|
|
output.push('');
|
|
}
|
|
} else {
|
|
output.push(str.slice(lastLastIndex));
|
|
}
|
|
separator.lastIndex = origLastIndex;
|
|
return output.length > limit ? output.slice(0, limit) : output;
|
|
};
|
|
add = self.addToken;
|
|
add(/\\([ABCE-RTUVXYZaeg-mopqyz]|c(?![A-Za-z])|u(?![\dA-Fa-f]{4})|x(?![\dA-Fa-f]{2}))/, function (match, scope) {
|
|
if (match[1] === 'B' && scope === defaultScope) {
|
|
return match[0];
|
|
}
|
|
throw new SyntaxError('Invalid escape ' + match[0]);
|
|
}, {
|
|
scope: 'all'
|
|
});
|
|
add(/\[(\^?)]/, function (match) {
|
|
return match[1] ? '[\\s\\S]' : '\\b\\B';
|
|
});
|
|
add(/\(\?#[^)]*\)/, function (match, scope, flags) {
|
|
return isQuantifierNext(match.input, match.index + match[0].length, flags) ? '' : '(?:)';
|
|
});
|
|
add(/\s+|#.*/, function (match, scope, flags) {
|
|
return isQuantifierNext(match.input, match.index + match[0].length, flags) ? '' : '(?:)';
|
|
}, {
|
|
flag: 'x'
|
|
});
|
|
add(/\./, function () {
|
|
return '[\\s\\S]';
|
|
}, {
|
|
flag: 's'
|
|
});
|
|
add(/\\k<([\w$]+)>/, function (match) {
|
|
var index = isNaN(match[1]) ? indexOf(this.captureNames, match[1]) + 1 : +match[1], endIndex = match.index + match[0].length;
|
|
if (!index || index > this.captureNames.length) {
|
|
throw new SyntaxError('Backreference to undefined group ' + match[0]);
|
|
}
|
|
return '\\' + index + (endIndex === match.input.length || isNaN(match.input.charAt(endIndex)) ? '' : '(?:)');
|
|
});
|
|
add(/\\(\d+)/, function (match, scope) {
|
|
if (!(scope === defaultScope && /^[1-9]/.test(match[1]) && +match[1] <= this.captureNames.length) && match[1] !== '0') {
|
|
throw new SyntaxError('Cannot use octal escape or backreference to undefined group ' + match[0]);
|
|
}
|
|
return match[0];
|
|
}, {
|
|
scope: 'all'
|
|
});
|
|
add(/\(\?P?<([\w$]+)>/, function (match) {
|
|
if (!isNaN(match[1])) {
|
|
throw new SyntaxError('Cannot use integer as capture name ' + match[0]);
|
|
}
|
|
if (match[1] === 'length' || match[1] === '__proto__') {
|
|
throw new SyntaxError('Cannot use reserved word as capture name ' + match[0]);
|
|
}
|
|
if (indexOf(this.captureNames, match[1]) > -1) {
|
|
throw new SyntaxError('Cannot use same name for multiple groups ' + match[0]);
|
|
}
|
|
this.captureNames.push(match[1]);
|
|
this.hasNamedCapture = true;
|
|
return '(';
|
|
});
|
|
add(/\((?!\?)/, function (match, scope, flags) {
|
|
if (flags.indexOf('n') > -1) {
|
|
return '(?:';
|
|
}
|
|
this.captureNames.push(null);
|
|
return '(';
|
|
}, {
|
|
optionalFlags: 'n'
|
|
});
|
|
return self;
|
|
}();
|
|
var Namespace = Shumway.AVM2.ABC.Namespace;
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
(function (Runtime) {
|
|
var Option = Shumway.Options.Option;
|
|
var OptionSet = Shumway.Options.OptionSet;
|
|
var runtimeOptions = systemOptions.register(new OptionSet('Runtime Options'));
|
|
var traceScope = runtimeOptions.register(new Option('ts', 'traceScope', 'boolean', false, 'trace scope execution'));
|
|
Runtime.traceExecution = runtimeOptions.register(new Option('tx', 'traceExecution', 'number', 0, 'trace script execution'));
|
|
Runtime.traceCallExecution = runtimeOptions.register(new Option('txc', 'traceCallExecution', 'number', 0, 'trace call execution'));
|
|
var functionBreak = runtimeOptions.register(new Option('fb', 'functionBreak', 'number', -1, 'Inserts a debugBreak at function index #.'));
|
|
var compileOnly = runtimeOptions.register(new Option('co', 'compileOnly', 'number', -1, 'Compiles only function number.'));
|
|
var compileUntil = runtimeOptions.register(new Option('cu', 'compileUntil', 'number', -1, 'Compiles only until a function number.'));
|
|
Runtime.debuggerMode = runtimeOptions.register(new Option('dm', 'debuggerMode', 'boolean', false, 'matches avm2 debugger build semantics'));
|
|
Runtime.enableVerifier = runtimeOptions.register(new Option('verify', 'verify', 'boolean', false, 'Enable verifier.'));
|
|
Runtime.globalMultinameAnalysis = runtimeOptions.register(new Option('ga', 'globalMultinameAnalysis', 'boolean', false, 'Global multiname analysis.'));
|
|
var traceInlineCaching = runtimeOptions.register(new Option('tic', 'traceInlineCaching', 'boolean', false, 'Trace inline caching execution.'));
|
|
Runtime.codeCaching = runtimeOptions.register(new Option('cc', 'codeCaching', 'boolean', false, 'Enable code caching.'));
|
|
var compilerEnableExceptions = runtimeOptions.register(new Option('cex', 'exceptions', 'boolean', false, 'Compile functions with catch blocks.'));
|
|
var compilerMaximumMethodSize = runtimeOptions.register(new Option('cmms', 'maximumMethodSize', 'number', 4 * 1024, 'Compiler maximum method size.'));
|
|
Runtime.traceClasses = runtimeOptions.register(new Option('tc', 'traceClasses', 'boolean', false, 'trace class creation'));
|
|
Runtime.traceDomain = runtimeOptions.register(new Option('td', 'traceDomain', 'boolean', false, 'trace domain property access'));
|
|
Runtime.sealConstTraits = false;
|
|
Runtime.useAsAdd = true;
|
|
var useSurrogates = true;
|
|
var callCounter = new Shumway.Metrics.Counter(true);
|
|
var Multiname = Shumway.AVM2.ABC.Multiname;
|
|
var Namespace = Shumway.AVM2.ABC.Namespace;
|
|
var MethodInfo = Shumway.AVM2.ABC.MethodInfo;
|
|
var ClassInfo = Shumway.AVM2.ABC.ClassInfo;
|
|
var InstanceInfo = Shumway.AVM2.ABC.InstanceInfo;
|
|
var ScriptInfo = Shumway.AVM2.ABC.ScriptInfo;
|
|
var SORT = Shumway.AVM2.ABC.SORT;
|
|
var Trait = Shumway.AVM2.ABC.Trait;
|
|
var IndentingWriter = Shumway.IndentingWriter;
|
|
var hasOwnProperty = Shumway.ObjectUtilities.hasOwnProperty;
|
|
var createMap = Shumway.ObjectUtilities.createMap;
|
|
var cloneObject = Shumway.ObjectUtilities.cloneObject;
|
|
var copyProperties = Shumway.ObjectUtilities.copyProperties;
|
|
var createEmptyObject = Shumway.ObjectUtilities.createEmptyObject;
|
|
var boxValue = Shumway.ObjectUtilities.boxValue;
|
|
var bindSafely = Shumway.FunctionUtilities.bindSafely;
|
|
var defineNonEnumerableGetterOrSetter = Shumway.ObjectUtilities.defineNonEnumerableGetterOrSetter;
|
|
var defineNonEnumerableProperty = Shumway.ObjectUtilities.defineNonEnumerableProperty;
|
|
var defineReadOnlyProperty = Shumway.ObjectUtilities.defineReadOnlyProperty;
|
|
var defineNonEnumerableGetter = Shumway.ObjectUtilities.defineNonEnumerableGetter;
|
|
var makeForwardingGetter = Shumway.FunctionUtilities.makeForwardingGetter;
|
|
var makeForwardingSetter = Shumway.FunctionUtilities.makeForwardingSetter;
|
|
var toSafeString = Shumway.StringUtilities.toSafeString;
|
|
var toSafeArrayString = Shumway.StringUtilities.toSafeArrayString;
|
|
var TRAIT = Shumway.AVM2.ABC.TRAIT;
|
|
Runtime.VM_SLOTS = 'asSlots';
|
|
Runtime.VM_LENGTH = 'asLength';
|
|
Runtime.VM_BINDINGS = 'asBindings';
|
|
Runtime.VM_NATIVE_PROTOTYPE_FLAG = 'asIsNative';
|
|
Runtime.VM_OPEN_METHODS = 'asOpenMethods';
|
|
Runtime.VM_IS_CLASS = 'asIsClass';
|
|
Runtime.VM_IS_PROXY = 'asIsProxy';
|
|
Runtime.VM_CALL_PROXY = 'asCallProxy';
|
|
Runtime.VM_OPEN_METHOD_PREFIX = 'm';
|
|
Runtime.VM_MEMOIZER_PREFIX = 'z';
|
|
Runtime.VM_OPEN_SET_METHOD_PREFIX = 's';
|
|
Runtime.VM_OPEN_GET_METHOD_PREFIX = 'g';
|
|
Runtime.VM_NATIVE_BUILTIN_ORIGINALS = 'asOriginals';
|
|
Runtime.VM_METHOD_OVERRIDES = createEmptyObject();
|
|
var vmNextInterpreterFunctionId = 1;
|
|
var vmNextCompiledFunctionId = 1;
|
|
var totalFunctionCount = 0;
|
|
var compiledFunctionCount = 0;
|
|
var compilationCount = 0;
|
|
function isClass(object) {
|
|
true;
|
|
return Object.hasOwnProperty.call(object, Runtime.VM_IS_CLASS);
|
|
}
|
|
Runtime.isClass = isClass;
|
|
function isNativePrototype(object) {
|
|
return Object.prototype.hasOwnProperty.call(object, Runtime.VM_NATIVE_PROTOTYPE_FLAG);
|
|
}
|
|
Runtime.isNativePrototype = isNativePrototype;
|
|
var traitsWriter = null;
|
|
var callWriter = null;
|
|
function patch(patchTargets, value) {
|
|
true;
|
|
for (var i = 0; i < patchTargets.length; i++) {
|
|
var patchTarget = patchTargets[i];
|
|
if (Runtime.traceExecution.value >= 3) {
|
|
var str = 'Patching: ';
|
|
if (patchTarget.name) {
|
|
str += patchTarget.name;
|
|
} else if (patchTarget.get) {
|
|
str += 'get ' + patchTarget.get;
|
|
} else if (patchTarget.set) {
|
|
str += 'set ' + patchTarget.set;
|
|
}
|
|
traitsWriter && traitsWriter.redLn(str);
|
|
}
|
|
if (patchTarget.get) {
|
|
defineNonEnumerableGetterOrSetter(patchTarget.object, patchTarget.get, value, true);
|
|
} else if (patchTarget.set) {
|
|
defineNonEnumerableGetterOrSetter(patchTarget.object, patchTarget.set, value, false);
|
|
} else {
|
|
defineNonEnumerableProperty(patchTarget.object, patchTarget.name, value);
|
|
}
|
|
}
|
|
}
|
|
Runtime.patch = patch;
|
|
function applyNonMemoizedMethodTrait(qn, trait, object, scope, natives) {
|
|
true;
|
|
if (trait.isMethod()) {
|
|
var trampoline = Shumway.AVM2.Runtime.makeTrampoline(function (self) {
|
|
var fn = getTraitFunction(trait, scope, natives);
|
|
patch(self.patchTargets, fn);
|
|
return fn;
|
|
}, trait.methodInfo.parameters.length);
|
|
trampoline.patchTargets = [
|
|
{
|
|
object: object,
|
|
name: qn
|
|
},
|
|
{
|
|
object: object,
|
|
name: Runtime.VM_OPEN_METHOD_PREFIX + qn
|
|
}
|
|
];
|
|
var closure = bindSafely(trampoline, object);
|
|
defineReadOnlyProperty(closure, Runtime.VM_LENGTH, trampoline.asLength);
|
|
defineReadOnlyProperty(closure, Multiname.getPublicQualifiedName('prototype'), null);
|
|
defineNonEnumerableProperty(object, qn, closure);
|
|
defineNonEnumerableProperty(object, Runtime.VM_OPEN_METHOD_PREFIX + qn, closure);
|
|
} else if (trait.isGetter() || trait.isSetter()) {
|
|
var trampoline = Shumway.AVM2.Runtime.makeTrampoline(function (self) {
|
|
var fn = getTraitFunction(trait, scope, natives);
|
|
patch(self.patchTargets, fn);
|
|
return fn;
|
|
}, trait.isSetter() ? 1 : 0);
|
|
if (trait.isGetter()) {
|
|
trampoline.patchTargets = [
|
|
{
|
|
object: object,
|
|
get: qn
|
|
}
|
|
];
|
|
} else {
|
|
trampoline.patchTargets = [
|
|
{
|
|
object: object,
|
|
set: qn
|
|
}
|
|
];
|
|
}
|
|
defineNonEnumerableGetterOrSetter(object, qn, trampoline, trait.isGetter());
|
|
} else {
|
|
Shumway.Debug.unexpected(trait);
|
|
}
|
|
}
|
|
Runtime.applyNonMemoizedMethodTrait = applyNonMemoizedMethodTrait;
|
|
function applyMemoizedMethodTrait(qn, trait, object, scope, natives) {
|
|
true;
|
|
if (trait.isMethod()) {
|
|
var memoizerTarget = {
|
|
value: null
|
|
};
|
|
var trampoline = Shumway.AVM2.Runtime.makeTrampoline(function (self) {
|
|
var fn = getTraitFunction(trait, scope, natives);
|
|
patch(self.patchTargets, fn);
|
|
return fn;
|
|
}, trait.methodInfo.parameters.length, String(trait.name));
|
|
memoizerTarget.value = trampoline;
|
|
var openMethods = object.asOpenMethods;
|
|
openMethods[qn] = trampoline;
|
|
defineNonEnumerableProperty(object, Runtime.VM_OPEN_METHOD_PREFIX + qn, trampoline);
|
|
defineNonEnumerableGetter(object, qn, Shumway.AVM2.Runtime.makeMemoizer(qn, memoizerTarget));
|
|
trampoline.patchTargets = [
|
|
{
|
|
object: memoizerTarget,
|
|
name: 'value'
|
|
},
|
|
{
|
|
object: openMethods,
|
|
name: qn
|
|
},
|
|
{
|
|
object: object,
|
|
name: Runtime.VM_OPEN_METHOD_PREFIX + qn
|
|
}
|
|
];
|
|
} else if (trait.isGetter() || trait.isSetter()) {
|
|
var trampoline = Shumway.AVM2.Runtime.makeTrampoline(function (self) {
|
|
var fn = getTraitFunction(trait, scope, natives);
|
|
patch(self.patchTargets, fn);
|
|
return fn;
|
|
}, 0, String(trait.name));
|
|
if (trait.isGetter()) {
|
|
defineNonEnumerableProperty(object, Runtime.VM_OPEN_GET_METHOD_PREFIX + qn, trampoline);
|
|
trampoline.patchTargets = [
|
|
{
|
|
object: object,
|
|
get: qn
|
|
},
|
|
{
|
|
object: object,
|
|
name: Runtime.VM_OPEN_GET_METHOD_PREFIX + qn
|
|
}
|
|
];
|
|
} else {
|
|
defineNonEnumerableProperty(object, Runtime.VM_OPEN_SET_METHOD_PREFIX + qn, trampoline);
|
|
trampoline.patchTargets = [
|
|
{
|
|
object: object,
|
|
set: qn
|
|
},
|
|
{
|
|
object: object,
|
|
name: Runtime.VM_OPEN_SET_METHOD_PREFIX + qn
|
|
}
|
|
];
|
|
}
|
|
defineNonEnumerableGetterOrSetter(object, qn, trampoline, trait.isGetter());
|
|
}
|
|
}
|
|
Runtime.applyMemoizedMethodTrait = applyMemoizedMethodTrait;
|
|
function getNamespaceResolutionMap(namespaces) {
|
|
var self = this;
|
|
var map = self.resolutionMap[namespaces.runtimeId];
|
|
if (map)
|
|
return map;
|
|
map = self.resolutionMap[namespaces.runtimeId] = Shumway.ObjectUtilities.createMap();
|
|
var bindings = self.bindings;
|
|
for (var key in bindings.map) {
|
|
var multiname = key;
|
|
var trait = bindings.map[key].trait;
|
|
if (trait.isGetter() || trait.isSetter()) {
|
|
multiname = multiname.substring(Shumway.AVM2.Runtime.Binding.KEY_PREFIX_LENGTH);
|
|
}
|
|
multiname = Multiname.fromQualifiedName(multiname);
|
|
if (multiname.getNamespace().inNamespaceSet(namespaces)) {
|
|
map[multiname.getName()] = Multiname.getQualifiedName(trait.name);
|
|
}
|
|
}
|
|
return map;
|
|
}
|
|
Runtime.getNamespaceResolutionMap = getNamespaceResolutionMap;
|
|
function resolveMultinameProperty(namespaces, name, flags) {
|
|
var self = this;
|
|
if (typeof name === 'object') {
|
|
name = String(name);
|
|
}
|
|
if (Shumway.isNumeric(name)) {
|
|
return Shumway.toNumber(name);
|
|
}
|
|
if (!namespaces) {
|
|
return Multiname.getPublicQualifiedName(name);
|
|
}
|
|
if (namespaces.length > 1) {
|
|
var resolved = self.getNamespaceResolutionMap(namespaces)[name];
|
|
if (resolved)
|
|
return resolved;
|
|
return Multiname.getPublicQualifiedName(name);
|
|
} else {
|
|
return Multiname.qualifyName(namespaces[0], name);
|
|
}
|
|
}
|
|
Runtime.resolveMultinameProperty = resolveMultinameProperty;
|
|
function asGetPublicProperty(name) {
|
|
var self = this;
|
|
return self.asGetProperty(undefined, name, 0);
|
|
}
|
|
Runtime.asGetPublicProperty = asGetPublicProperty;
|
|
function asGetProperty(namespaces, name, flags) {
|
|
var self = this;
|
|
var resolved = self.resolveMultinameProperty(namespaces, name, flags);
|
|
if (self.asGetNumericProperty && Multiname.isNumeric(resolved)) {
|
|
return self.asGetNumericProperty(resolved);
|
|
}
|
|
return self[resolved];
|
|
}
|
|
Runtime.asGetProperty = asGetProperty;
|
|
function asGetPropertyLikelyNumeric(namespaces, name, flags) {
|
|
var self = this;
|
|
if (typeof name === 'number') {
|
|
return self.asGetNumericProperty(name);
|
|
}
|
|
return asGetProperty.call(self, namespaces, name, flags);
|
|
}
|
|
Runtime.asGetPropertyLikelyNumeric = asGetPropertyLikelyNumeric;
|
|
function asGetResolvedStringProperty(resolved) {
|
|
true;
|
|
return this[resolved];
|
|
}
|
|
Runtime.asGetResolvedStringProperty = asGetResolvedStringProperty;
|
|
function asCallResolvedStringProperty(resolved, isLex, args) {
|
|
var self = this;
|
|
var receiver = isLex ? null : this;
|
|
var openMethods = self.asOpenMethods;
|
|
var method;
|
|
if (receiver && openMethods && openMethods[resolved]) {
|
|
method = openMethods[resolved];
|
|
} else {
|
|
method = self[resolved];
|
|
}
|
|
return method.apply(receiver, args);
|
|
}
|
|
Runtime.asCallResolvedStringProperty = asCallResolvedStringProperty;
|
|
function asGetResolvedStringPropertyFallback(resolved) {
|
|
var self = this;
|
|
var name = Multiname.getNameFromPublicQualifiedName(resolved);
|
|
return self.asGetProperty([
|
|
Namespace.PUBLIC
|
|
], name, 0);
|
|
}
|
|
Runtime.asGetResolvedStringPropertyFallback = asGetResolvedStringPropertyFallback;
|
|
function asSetPublicProperty(name, value) {
|
|
var self = this;
|
|
return self.asSetProperty(undefined, name, 0, value);
|
|
}
|
|
Runtime.asSetPublicProperty = asSetPublicProperty;
|
|
function asSetProperty(namespaces, name, flags, value) {
|
|
var self = this;
|
|
if (typeof name === 'object') {
|
|
name = String(name);
|
|
}
|
|
var resolved = self.resolveMultinameProperty(namespaces, name, flags);
|
|
if (self.asSetNumericProperty && Multiname.isNumeric(resolved)) {
|
|
return self.asSetNumericProperty(resolved, value);
|
|
}
|
|
var slotInfo = self.asSlots.byQN[resolved];
|
|
if (slotInfo) {
|
|
if (slotInfo.isConst) {
|
|
}
|
|
var type = slotInfo.type;
|
|
if (type && type.coerce) {
|
|
value = type.coerce(value);
|
|
}
|
|
}
|
|
self[resolved] = value;
|
|
}
|
|
Runtime.asSetProperty = asSetProperty;
|
|
function asSetPropertyLikelyNumeric(namespaces, name, flags, value) {
|
|
var self = this;
|
|
if (typeof name === 'number') {
|
|
self.asSetNumericProperty(name, value);
|
|
return;
|
|
}
|
|
return asSetProperty.call(self, namespaces, name, flags, value);
|
|
}
|
|
Runtime.asSetPropertyLikelyNumeric = asSetPropertyLikelyNumeric;
|
|
function asDefinePublicProperty(name, descriptor) {
|
|
var self = this;
|
|
return self.asDefineProperty(undefined, name, 0, descriptor);
|
|
}
|
|
Runtime.asDefinePublicProperty = asDefinePublicProperty;
|
|
function asDefineProperty(namespaces, name, flags, descriptor) {
|
|
var self = this;
|
|
if (typeof name === 'object') {
|
|
name = String(name);
|
|
}
|
|
var resolved = self.resolveMultinameProperty(namespaces, name, flags);
|
|
Object.defineProperty(self, resolved, descriptor);
|
|
}
|
|
Runtime.asDefineProperty = asDefineProperty;
|
|
function asCallPublicProperty(name, args) {
|
|
var self = this;
|
|
return self.asCallProperty(undefined, name, 0, false, args);
|
|
}
|
|
Runtime.asCallPublicProperty = asCallPublicProperty;
|
|
function asCallProperty(namespaces, name, flags, isLex, args) {
|
|
var self = this;
|
|
if (Runtime.traceCallExecution.value) {
|
|
var receiverClassName = self.class ? self.class.className + ' ' : '';
|
|
callWriter.enter('call ' + receiverClassName + name + '(' + toSafeArrayString(args) + ') #' + callCounter.count(name));
|
|
}
|
|
var receiver = isLex ? null : self;
|
|
var result;
|
|
if (isProxyObject(self)) {
|
|
result = self[Runtime.VM_CALL_PROXY](new Multiname(namespaces, name, flags), receiver, args);
|
|
} else {
|
|
var method;
|
|
var resolved = self.resolveMultinameProperty(namespaces, name, flags);
|
|
if (self.asGetNumericProperty && Multiname.isNumeric(resolved)) {
|
|
method = self.asGetNumericProperty(resolved);
|
|
} else {
|
|
var openMethods = self.asOpenMethods;
|
|
if (receiver && openMethods && openMethods[resolved]) {
|
|
method = openMethods[resolved];
|
|
} else {
|
|
method = self[resolved];
|
|
}
|
|
}
|
|
result = method.apply(receiver, args);
|
|
}
|
|
Runtime.traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result));
|
|
return result;
|
|
}
|
|
Runtime.asCallProperty = asCallProperty;
|
|
function asCallSuper(scope, namespaces, name, flags, args) {
|
|
var self = this;
|
|
if (Runtime.traceCallExecution.value) {
|
|
var receiverClassName = self.class ? self.class.className + ' ' : '';
|
|
callWriter.enter('call super ' + receiverClassName + name + '(' + toSafeArrayString(args) + ') #' + callCounter.count(name));
|
|
}
|
|
var baseClass = scope.object.baseClass;
|
|
var resolved = baseClass.traitsPrototype.resolveMultinameProperty(namespaces, name, flags);
|
|
var openMethods = baseClass.traitsPrototype.asOpenMethods;
|
|
var method = openMethods[resolved];
|
|
var result = method.apply(this, args);
|
|
Runtime.traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result));
|
|
return result;
|
|
}
|
|
Runtime.asCallSuper = asCallSuper;
|
|
function asSetSuper(scope, namespaces, name, flags, value) {
|
|
var self = this;
|
|
if (Runtime.traceCallExecution.value) {
|
|
var receiverClassName = self.class ? self.class.className + ' ' : '';
|
|
callWriter.enter('set super ' + receiverClassName + name + '(' + toSafeString(value) + ') #' + callCounter.count(name));
|
|
}
|
|
var baseClass = scope.object.baseClass;
|
|
var resolved = baseClass.traitsPrototype.resolveMultinameProperty(namespaces, name, flags);
|
|
if (self.asSlots.byQN[resolved]) {
|
|
this.asSetProperty(namespaces, name, flags, value);
|
|
} else {
|
|
baseClass.traitsPrototype[Runtime.VM_OPEN_SET_METHOD_PREFIX + resolved].call(this, value);
|
|
}
|
|
Runtime.traceCallExecution.value > 0 && callWriter.leave('');
|
|
}
|
|
Runtime.asSetSuper = asSetSuper;
|
|
function asGetSuper(scope, namespaces, name, flags) {
|
|
var self = this;
|
|
if (Runtime.traceCallExecution.value) {
|
|
var receiver = self.class ? self.class.className + ' ' : '';
|
|
callWriter.enter('get super ' + receiver + name + ' #' + callCounter.count(name));
|
|
}
|
|
var baseClass = scope.object.baseClass;
|
|
var resolved = baseClass.traitsPrototype.resolveMultinameProperty(namespaces, name, flags);
|
|
var result;
|
|
if (self.asSlots.byQN[resolved]) {
|
|
result = this.asGetProperty(namespaces, name, flags);
|
|
} else {
|
|
result = baseClass.traitsPrototype[Runtime.VM_OPEN_GET_METHOD_PREFIX + resolved].call(this);
|
|
}
|
|
Runtime.traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result));
|
|
return result;
|
|
}
|
|
Runtime.asGetSuper = asGetSuper;
|
|
function construct(cls, args) {
|
|
if (cls.classInfo) {
|
|
var qn = Multiname.getQualifiedName(cls.classInfo.instanceInfo.name);
|
|
if (qn === Multiname.String) {
|
|
return String.apply(null, args);
|
|
}
|
|
if (qn === Multiname.Boolean) {
|
|
return Boolean.apply(null, args);
|
|
}
|
|
if (qn === Multiname.Number) {
|
|
return Number.apply(null, args);
|
|
}
|
|
}
|
|
var c = cls.instanceConstructor;
|
|
var a = args;
|
|
switch (args.length) {
|
|
case 0:
|
|
return new c();
|
|
case 1:
|
|
return new c(a[0]);
|
|
case 2:
|
|
return new c(a[0], a[1]);
|
|
case 3:
|
|
return new c(a[0], a[1], a[2]);
|
|
case 4:
|
|
return new c(a[0], a[1], a[2], a[3]);
|
|
case 5:
|
|
return new c(a[0], a[1], a[2], a[3], a[4]);
|
|
case 6:
|
|
return new c(a[0], a[1], a[2], a[3], a[4], a[5]);
|
|
case 7:
|
|
return new c(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
|
|
case 8:
|
|
return new c(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
|
|
case 9:
|
|
return new c(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
|
|
case 10:
|
|
return new c(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
|
|
}
|
|
var applyArguments = [];
|
|
for (var i = 0; i < args.length; i++) {
|
|
applyArguments[i + 1] = args[i];
|
|
}
|
|
return new (Function.bind.apply(c, applyArguments))();
|
|
}
|
|
Runtime.construct = construct;
|
|
function asConstructProperty(namespaces, name, flags, args) {
|
|
var self = this;
|
|
var constructor = self.asGetProperty(namespaces, name, flags);
|
|
if (Runtime.traceCallExecution.value) {
|
|
callWriter.enter('construct ' + name + '(' + toSafeArrayString(args) + ') #' + callCounter.count(name));
|
|
}
|
|
var result = construct(constructor, args);
|
|
Runtime.traceCallExecution.value > 0 && callWriter.leave('return ' + toSafeString(result));
|
|
return result;
|
|
}
|
|
Runtime.asConstructProperty = asConstructProperty;
|
|
function nonProxyingHasProperty(object, name) {
|
|
return name in object;
|
|
}
|
|
Runtime.nonProxyingHasProperty = nonProxyingHasProperty;
|
|
function asHasProperty(namespaces, name, flags, nonProxy) {
|
|
var self = this;
|
|
if (self.hasProperty) {
|
|
return self.hasProperty(namespaces, name, flags);
|
|
}
|
|
if (nonProxy) {
|
|
return nonProxyingHasProperty(self, self.resolveMultinameProperty(namespaces, name, flags));
|
|
} else {
|
|
return self.resolveMultinameProperty(namespaces, name, flags) in this;
|
|
}
|
|
}
|
|
Runtime.asHasProperty = asHasProperty;
|
|
function asDeleteProperty(namespaces, name, flags) {
|
|
var self = this;
|
|
if (self.asHasTraitProperty(namespaces, name, flags)) {
|
|
return false;
|
|
}
|
|
var resolved = self.resolveMultinameProperty(namespaces, name, flags);
|
|
return delete self[resolved];
|
|
}
|
|
Runtime.asDeleteProperty = asDeleteProperty;
|
|
function asHasTraitProperty(namespaces, name, flags) {
|
|
var self = this;
|
|
var resolved = self.resolveMultinameProperty(namespaces, name, flags);
|
|
return self.asBindings.indexOf(resolved) >= 0;
|
|
}
|
|
Runtime.asHasTraitProperty = asHasTraitProperty;
|
|
function asGetNumericProperty(i) {
|
|
return this[i];
|
|
}
|
|
Runtime.asGetNumericProperty = asGetNumericProperty;
|
|
function asSetNumericProperty(i, v) {
|
|
this[i] = v;
|
|
}
|
|
Runtime.asSetNumericProperty = asSetNumericProperty;
|
|
function asGetDescendants(namespaces, name, flags) {
|
|
Shumway.Debug.notImplemented('asGetDescendants');
|
|
}
|
|
Runtime.asGetDescendants = asGetDescendants;
|
|
function asNextNameIndex(index) {
|
|
var self = this;
|
|
if (index === 0) {
|
|
defineNonEnumerableProperty(self, 'asEnumerableKeys', self.asGetEnumerableKeys());
|
|
}
|
|
var asEnumerableKeys = self.asEnumerableKeys;
|
|
while (index < asEnumerableKeys.length) {
|
|
if (self.asHasProperty(undefined, asEnumerableKeys[index], 0)) {
|
|
return index + 1;
|
|
}
|
|
index++;
|
|
}
|
|
return 0;
|
|
}
|
|
Runtime.asNextNameIndex = asNextNameIndex;
|
|
function asNextName(index) {
|
|
var self = this;
|
|
var asEnumerableKeys = self.asEnumerableKeys;
|
|
true;
|
|
return asEnumerableKeys[index - 1];
|
|
}
|
|
Runtime.asNextName = asNextName;
|
|
function asNextValue(index) {
|
|
return this.asGetPublicProperty(this.asNextName(index));
|
|
}
|
|
Runtime.asNextValue = asNextValue;
|
|
function asGetEnumerableKeys() {
|
|
var self = this;
|
|
var boxedValue = self.valueOf();
|
|
if (typeof boxedValue === 'string' || typeof boxedValue === 'number') {
|
|
return [];
|
|
}
|
|
var keys = Object.keys(this);
|
|
var result = [];
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
if (Shumway.isNumeric(key)) {
|
|
result.push(key);
|
|
} else {
|
|
var name = Multiname.stripPublicQualifier(key);
|
|
if (name !== undefined) {
|
|
result.push(name);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
Runtime.asGetEnumerableKeys = asGetEnumerableKeys;
|
|
function asTypeOf(x) {
|
|
if (x) {
|
|
if (x.constructor === String) {
|
|
return 'string';
|
|
} else if (x.constructor === Number) {
|
|
return 'number';
|
|
} else if (x.constructor === Boolean) {
|
|
return 'boolean';
|
|
} else if (x instanceof XML || x instanceof XMLList) {
|
|
return 'xml';
|
|
}
|
|
}
|
|
return typeof x;
|
|
}
|
|
Runtime.asTypeOf = asTypeOf;
|
|
function publicizeProperties(object) {
|
|
var keys = Object.keys(object);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var k = keys[i];
|
|
if (!Multiname.isPublicQualifiedName(k)) {
|
|
var v = object[k];
|
|
object[Multiname.getPublicQualifiedName(k)] = v;
|
|
delete object[k];
|
|
}
|
|
}
|
|
}
|
|
Runtime.publicizeProperties = publicizeProperties;
|
|
function asGetSlot(object, index) {
|
|
return object[object.asSlots.byID[index].name];
|
|
}
|
|
Runtime.asGetSlot = asGetSlot;
|
|
function asSetSlot(object, index, value) {
|
|
var slotInfo = object.asSlots.byID[index];
|
|
if (slotInfo.const) {
|
|
return;
|
|
}
|
|
var name = slotInfo.name;
|
|
var type = slotInfo.type;
|
|
if (type && type.coerce) {
|
|
object[name] = type.coerce(value);
|
|
} else {
|
|
object[name] = value;
|
|
}
|
|
}
|
|
Runtime.asSetSlot = asSetSlot;
|
|
function throwError(name, error) {
|
|
if (true) {
|
|
var message = Shumway.AVM2.formatErrorMessage.apply(null, Array.prototype.slice.call(arguments, 1));
|
|
throwErrorFromVM(Shumway.AVM2.Runtime.AVM2.currentDomain(), name, message, error.code);
|
|
} else {
|
|
throwErrorFromVM(Shumway.AVM2.Runtime.AVM2.currentDomain(), name, Shumway.AVM2.getErrorMessage(error.code), error.code);
|
|
}
|
|
}
|
|
Runtime.throwError = throwError;
|
|
function throwErrorFromVM(domain, errorClass, message, id) {
|
|
var error = new (domain.getClass(errorClass)).instanceConstructor(message, id);
|
|
throw error;
|
|
}
|
|
Runtime.throwErrorFromVM = throwErrorFromVM;
|
|
function translateError(domain, error) {
|
|
if (error instanceof Error) {
|
|
var type = domain.getClass(error.name);
|
|
if (type) {
|
|
return new type.instanceConstructor(Shumway.AVM2.translateErrorMessage(error));
|
|
}
|
|
Shumway.Debug.unexpected('Can\'t translate error: ' + error);
|
|
}
|
|
return error;
|
|
}
|
|
Runtime.translateError = translateError;
|
|
function asIsInstanceOf(type, value) {
|
|
return type.isInstanceOf(value);
|
|
}
|
|
Runtime.asIsInstanceOf = asIsInstanceOf;
|
|
function asIsType(type, value) {
|
|
return type.isInstance(value);
|
|
}
|
|
Runtime.asIsType = asIsType;
|
|
function asAsType(type, value) {
|
|
return asIsType(type, value) ? value : null;
|
|
}
|
|
Runtime.asAsType = asAsType;
|
|
function asCoerceByMultiname(domain, multiname, value) {
|
|
true;
|
|
switch (Multiname.getQualifiedName(multiname)) {
|
|
case Multiname.Int:
|
|
return asCoerceInt(value);
|
|
case Multiname.Uint:
|
|
return asCoerceUint(value);
|
|
case Multiname.String:
|
|
return asCoerceString(value);
|
|
case Multiname.Number:
|
|
return asCoerceNumber(value);
|
|
case Multiname.Boolean:
|
|
return asCoerceBoolean(value);
|
|
case Multiname.Object:
|
|
return asCoerceObject(value);
|
|
}
|
|
return asCoerce(domain.getType(multiname), value);
|
|
}
|
|
Runtime.asCoerceByMultiname = asCoerceByMultiname;
|
|
function asCoerce(type, value) {
|
|
if (type.coerce) {
|
|
return type.coerce(value);
|
|
}
|
|
if (Shumway.isNullOrUndefined(value)) {
|
|
return null;
|
|
}
|
|
if (type.isInstance(value)) {
|
|
return value;
|
|
} else {
|
|
true;
|
|
}
|
|
}
|
|
Runtime.asCoerce = asCoerce;
|
|
function asCoerceString(x) {
|
|
if (typeof x === 'string') {
|
|
return x;
|
|
} else if (x == undefined) {
|
|
return null;
|
|
}
|
|
return x + '';
|
|
}
|
|
Runtime.asCoerceString = asCoerceString;
|
|
function asCoerceInt(x) {
|
|
return x | 0;
|
|
}
|
|
Runtime.asCoerceInt = asCoerceInt;
|
|
function asCoerceUint(x) {
|
|
return x >>> 0;
|
|
}
|
|
Runtime.asCoerceUint = asCoerceUint;
|
|
function asCoerceNumber(x) {
|
|
return +x;
|
|
}
|
|
Runtime.asCoerceNumber = asCoerceNumber;
|
|
function asCoerceBoolean(x) {
|
|
return !(!x);
|
|
}
|
|
Runtime.asCoerceBoolean = asCoerceBoolean;
|
|
function asCoerceObject(x) {
|
|
if (x == undefined) {
|
|
return null;
|
|
}
|
|
if (typeof x === 'string' || typeof x === 'number') {
|
|
return x;
|
|
}
|
|
return Object(x);
|
|
}
|
|
Runtime.asCoerceObject = asCoerceObject;
|
|
function asDefaultCompareFunction(a, b) {
|
|
return String(a).localeCompare(String(b));
|
|
}
|
|
Runtime.asDefaultCompareFunction = asDefaultCompareFunction;
|
|
function asCompare(a, b, options, compareFunction) {
|
|
true;
|
|
true;
|
|
var result = 0;
|
|
if (!compareFunction) {
|
|
compareFunction = asDefaultCompareFunction;
|
|
}
|
|
if (options & 1) {
|
|
a = String(a).toLowerCase();
|
|
b = String(b).toLowerCase();
|
|
}
|
|
if (options & 16) {
|
|
a = Shumway.toNumber(a);
|
|
b = Shumway.toNumber(b);
|
|
result = a < b ? -1 : a > b ? 1 : 0;
|
|
} else {
|
|
result = compareFunction(a, b);
|
|
}
|
|
if (options & 2) {
|
|
result *= -1;
|
|
}
|
|
return result;
|
|
}
|
|
Runtime.asCompare = asCompare;
|
|
function asAdd(l, r) {
|
|
if (typeof l === 'string' || typeof r === 'string') {
|
|
return String(l) + String(r);
|
|
}
|
|
return l + r;
|
|
}
|
|
Runtime.asAdd = asAdd;
|
|
function asHasNext2(object, index) {
|
|
if (Shumway.isNullOrUndefined(object)) {
|
|
return {
|
|
index: 0,
|
|
object: null
|
|
};
|
|
}
|
|
object = boxValue(object);
|
|
var nextIndex = object.asNextNameIndex(index);
|
|
if (nextIndex > 0) {
|
|
return {
|
|
index: nextIndex,
|
|
object: object
|
|
};
|
|
}
|
|
while (true) {
|
|
var object = Object.getPrototypeOf(object);
|
|
if (!object) {
|
|
return {
|
|
index: 0,
|
|
object: null
|
|
};
|
|
}
|
|
nextIndex = object.asNextNameIndex(0);
|
|
if (nextIndex > 0) {
|
|
return {
|
|
index: nextIndex,
|
|
object: object
|
|
};
|
|
}
|
|
}
|
|
return {
|
|
index: 0,
|
|
object: null
|
|
};
|
|
}
|
|
Runtime.asHasNext2 = asHasNext2;
|
|
function getDescendants(object, mn) {
|
|
if (!isXMLType(object)) {
|
|
throw 'Not XML object in getDescendants';
|
|
}
|
|
return object.descendants(mn);
|
|
}
|
|
Runtime.getDescendants = getDescendants;
|
|
function checkFilter(value) {
|
|
if (!value.class || !isXMLType(value)) {
|
|
throw 'TypeError operand of childFilter not of XML type';
|
|
}
|
|
return value;
|
|
}
|
|
Runtime.checkFilter = checkFilter;
|
|
function initializeGlobalObject(global) {
|
|
var VM_NATIVE_BUILTIN_SURROGATES = [
|
|
{
|
|
name: 'Object',
|
|
methods: [
|
|
'toString',
|
|
'valueOf'
|
|
]
|
|
},
|
|
{
|
|
name: 'Function',
|
|
methods: [
|
|
'toString',
|
|
'valueOf'
|
|
]
|
|
}
|
|
];
|
|
var originals = global[Runtime.VM_NATIVE_BUILTIN_ORIGINALS] = createEmptyObject();
|
|
VM_NATIVE_BUILTIN_SURROGATES.forEach(function (surrogate) {
|
|
var object = global[surrogate.name];
|
|
originals[surrogate.name] = createEmptyObject();
|
|
surrogate.methods.forEach(function (originalFunctionName) {
|
|
var originalFunction;
|
|
if (object.prototype.hasOwnProperty(originalFunctionName)) {
|
|
originalFunction = object.prototype[originalFunctionName];
|
|
} else {
|
|
originalFunction = originals['Object'][originalFunctionName];
|
|
}
|
|
originals[surrogate.name][originalFunctionName] = originalFunction;
|
|
var overrideFunctionName = Multiname.getPublicQualifiedName(originalFunctionName);
|
|
if (useSurrogates) {
|
|
global[surrogate.name].prototype[originalFunctionName] = function surrogate() {
|
|
if (this[overrideFunctionName]) {
|
|
return this[overrideFunctionName]();
|
|
}
|
|
return originalFunction.call(this);
|
|
};
|
|
}
|
|
});
|
|
});
|
|
[
|
|
'Object',
|
|
'Number',
|
|
'Boolean',
|
|
'String',
|
|
'Array',
|
|
'Date',
|
|
'RegExp'
|
|
].forEach(function (name) {
|
|
defineReadOnlyProperty(global[name].prototype, Runtime.VM_NATIVE_PROTOTYPE_FLAG, true);
|
|
});
|
|
defineNonEnumerableProperty(global.Object.prototype, 'getNamespaceResolutionMap', getNamespaceResolutionMap);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'resolveMultinameProperty', resolveMultinameProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asGetProperty', asGetProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asGetPublicProperty', asGetPublicProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asGetResolvedStringProperty', asGetResolvedStringProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asSetProperty', asSetProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asSetPublicProperty', asSetPublicProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asDefineProperty', asDefineProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asDefinePublicProperty', asDefinePublicProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asCallProperty', asCallProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asCallSuper', asCallSuper);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asGetSuper', asGetSuper);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asSetSuper', asSetSuper);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asCallPublicProperty', asCallPublicProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asCallResolvedStringProperty', asCallResolvedStringProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asConstructProperty', asConstructProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asHasProperty', asHasProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asHasTraitProperty', asHasTraitProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asDeleteProperty', asDeleteProperty);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asNextName', asNextName);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asNextValue', asNextValue);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asNextNameIndex', asNextNameIndex);
|
|
defineNonEnumerableProperty(global.Object.prototype, 'asGetEnumerableKeys', asGetEnumerableKeys);
|
|
[
|
|
'Array',
|
|
'Int8Array',
|
|
'Uint8Array',
|
|
'Uint8ClampedArray',
|
|
'Int16Array',
|
|
'Uint16Array',
|
|
'Int32Array',
|
|
'Uint32Array',
|
|
'Float32Array',
|
|
'Float64Array'
|
|
].forEach(function (name) {
|
|
if (!(name in global)) {
|
|
log(name + ' was not found in globals');
|
|
return;
|
|
}
|
|
defineNonEnumerableProperty(global[name].prototype, 'asGetNumericProperty', asGetNumericProperty);
|
|
defineNonEnumerableProperty(global[name].prototype, 'asSetNumericProperty', asSetNumericProperty);
|
|
defineNonEnumerableProperty(global[name].prototype, 'asGetProperty', asGetPropertyLikelyNumeric);
|
|
defineNonEnumerableProperty(global[name].prototype, 'asSetProperty', asSetPropertyLikelyNumeric);
|
|
});
|
|
global.Array.prototype.asGetProperty = function (namespaces, name, flags) {
|
|
if (typeof name === 'number') {
|
|
return this[name];
|
|
}
|
|
return asGetProperty.call(this, namespaces, name, flags);
|
|
};
|
|
global.Array.prototype.asSetProperty = function (namespaces, name, flags, value) {
|
|
if (typeof name === 'number') {
|
|
this[name] = value;
|
|
return;
|
|
}
|
|
return asSetProperty.call(this, namespaces, name, flags, value);
|
|
};
|
|
}
|
|
Runtime.initializeGlobalObject = initializeGlobalObject;
|
|
function nameInTraits(object, qn) {
|
|
if (object.hasOwnProperty(Runtime.VM_BINDINGS) && object.hasOwnProperty(qn)) {
|
|
return true;
|
|
}
|
|
var proto = Object.getPrototypeOf(object);
|
|
return proto.hasOwnProperty(Runtime.VM_BINDINGS) && proto.hasOwnProperty(qn);
|
|
}
|
|
Runtime.nameInTraits = nameInTraits;
|
|
function CatchScopeObject(domain, trait) {
|
|
if (trait) {
|
|
new Shumway.AVM2.Runtime.CatchBindings(new Shumway.AVM2.Runtime.Scope(null, this), trait).applyTo(domain, this);
|
|
}
|
|
}
|
|
Runtime.CatchScopeObject = CatchScopeObject;
|
|
var Global = function () {
|
|
function Global(script) {
|
|
this.scriptInfo = script;
|
|
script.global = this;
|
|
this.scriptBindings = new Shumway.AVM2.Runtime.ScriptBindings(script, new Shumway.AVM2.Runtime.Scope(null, this, false));
|
|
this.scriptBindings.applyTo(script.abc.applicationDomain, this);
|
|
script.loaded = true;
|
|
}
|
|
Global.prototype.toString = function () {
|
|
return '[object global]';
|
|
};
|
|
Global.prototype.isExecuted = function () {
|
|
return this.scriptInfo.executed;
|
|
};
|
|
Global.prototype.isExecuting = function () {
|
|
return this.scriptInfo.executing;
|
|
};
|
|
Global.prototype.ensureExecuted = function () {
|
|
Shumway.AVM2.Runtime.ensureScriptIsExecuted(this.scriptInfo);
|
|
};
|
|
return Global;
|
|
}();
|
|
Runtime.Global = Global;
|
|
defineNonEnumerableProperty(Global.prototype, Multiname.getPublicQualifiedName('toString'), function () {
|
|
return this.toString();
|
|
});
|
|
var LazyInitializer = function () {
|
|
function LazyInitializer(target) {
|
|
this.target = target;
|
|
}
|
|
LazyInitializer.create = function (target) {
|
|
if (target.asLazyInitializer) {
|
|
return target.asLazyInitializer;
|
|
}
|
|
return target.asLazyInitializer = new LazyInitializer(target);
|
|
};
|
|
LazyInitializer.prototype.getName = function () {
|
|
if (this.name) {
|
|
return this.name;
|
|
}
|
|
var target = this.target, initialize;
|
|
if (this.target instanceof ScriptInfo) {
|
|
var scriptInfo = target;
|
|
this.name = '$' + Shumway.StringUtilities.variableLengthEncodeInt32(scriptInfo.hash);
|
|
initialize = function () {
|
|
Shumway.AVM2.Runtime.ensureScriptIsExecuted(target, 'Lazy Initializer');
|
|
return scriptInfo.global;
|
|
};
|
|
} else if (this.target instanceof ClassInfo) {
|
|
var classInfo = target;
|
|
this.name = '$' + Shumway.StringUtilities.variableLengthEncodeInt32(classInfo.hash);
|
|
initialize = function () {
|
|
if (classInfo.classObject) {
|
|
return classInfo.classObject;
|
|
}
|
|
return classInfo.abc.applicationDomain.getProperty(classInfo.instanceInfo.name);
|
|
};
|
|
} else {
|
|
Shumway.Debug.notImplemented(String(target));
|
|
}
|
|
var name = this.name;
|
|
Object.defineProperty(LazyInitializer._holder, name, {
|
|
get: function () {
|
|
var value = initialize();
|
|
Object.defineProperty(LazyInitializer._holder, name, {
|
|
value: value,
|
|
writable: true
|
|
});
|
|
return value;
|
|
},
|
|
configurable: true
|
|
});
|
|
return name;
|
|
};
|
|
LazyInitializer._holder = jsGlobal;
|
|
return LazyInitializer;
|
|
}();
|
|
Runtime.LazyInitializer = LazyInitializer;
|
|
function forEachPublicProperty(object, fn, self) {
|
|
if (!object.asBindings) {
|
|
for (var key in object) {
|
|
fn.call(self, key, object[key]);
|
|
}
|
|
return;
|
|
}
|
|
for (var key in object) {
|
|
if (Shumway.isNumeric(key)) {
|
|
fn.call(self, key, object[key]);
|
|
} else if (Multiname.isPublicQualifiedName(key) && object.asBindings.indexOf(key) < 0) {
|
|
var name = Multiname.stripPublicQualifier(key);
|
|
fn.call(self, name, object[key]);
|
|
}
|
|
}
|
|
}
|
|
Runtime.forEachPublicProperty = forEachPublicProperty;
|
|
function wrapJSObject(object) {
|
|
var wrapper = Object.create(object);
|
|
for (var i in object) {
|
|
Object.defineProperty(wrapper, Multiname.getPublicQualifiedName(i), function (object, i) {
|
|
return {
|
|
get: function () {
|
|
return object[i];
|
|
},
|
|
set: function (value) {
|
|
object[i] = value;
|
|
},
|
|
enumerable: true
|
|
};
|
|
}(object, i));
|
|
}
|
|
return wrapper;
|
|
}
|
|
Runtime.wrapJSObject = wrapJSObject;
|
|
function asCreateActivation(methodInfo) {
|
|
return Object.create(methodInfo.activationPrototype);
|
|
}
|
|
Runtime.asCreateActivation = asCreateActivation;
|
|
var GlobalMultinameResolver = function () {
|
|
function GlobalMultinameResolver() {
|
|
}
|
|
GlobalMultinameResolver.updateTraits = function (traits) {
|
|
for (var i = 0; i < traits.length; i++) {
|
|
var trait = traits[i];
|
|
var name = trait.name.name;
|
|
var namespace = trait.name.getNamespace();
|
|
if (!namespace.isDynamic()) {
|
|
GlobalMultinameResolver.hasNonDynamicNamespaces[name] = true;
|
|
if (GlobalMultinameResolver.wasResolved[name]) {
|
|
Shumway.Debug.notImplemented('We have to the undo the optimization, ' + name + ' can now bind to ' + namespace);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
GlobalMultinameResolver.loadAbc = function (abc) {
|
|
if (!Runtime.globalMultinameAnalysis.value) {
|
|
return;
|
|
}
|
|
var scripts = abc.scripts;
|
|
var classes = abc.classes;
|
|
var methods = abc.methods;
|
|
for (var i = 0; i < scripts.length; i++) {
|
|
GlobalMultinameResolver.updateTraits(scripts[i].traits);
|
|
}
|
|
for (var i = 0; i < classes.length; i++) {
|
|
GlobalMultinameResolver.updateTraits(classes[i].traits);
|
|
GlobalMultinameResolver.updateTraits(classes[i].instanceInfo.traits);
|
|
}
|
|
for (var i = 0; i < methods.length; i++) {
|
|
if (methods[i].traits) {
|
|
GlobalMultinameResolver.updateTraits(methods[i].traits);
|
|
}
|
|
}
|
|
};
|
|
GlobalMultinameResolver.resolveMultiname = function (multiname) {
|
|
var name = multiname.name;
|
|
if (GlobalMultinameResolver.hasNonDynamicNamespaces[name]) {
|
|
return;
|
|
}
|
|
GlobalMultinameResolver.wasResolved[name] = true;
|
|
return new Multiname([
|
|
Namespace.PUBLIC
|
|
], multiname.name);
|
|
};
|
|
GlobalMultinameResolver.hasNonDynamicNamespaces = createEmptyObject();
|
|
GlobalMultinameResolver.wasResolved = createEmptyObject();
|
|
return GlobalMultinameResolver;
|
|
}();
|
|
Runtime.GlobalMultinameResolver = GlobalMultinameResolver;
|
|
var ActivationInfo = function () {
|
|
function ActivationInfo(methodInfo) {
|
|
this.methodInfo = methodInfo;
|
|
}
|
|
return ActivationInfo;
|
|
}();
|
|
Runtime.ActivationInfo = ActivationInfo;
|
|
function sliceArguments(args, offset) {
|
|
if (typeof offset === 'undefined') {
|
|
offset = 0;
|
|
}
|
|
return Array.prototype.slice.call(args, offset);
|
|
}
|
|
Runtime.sliceArguments = sliceArguments;
|
|
function canCompile(mi) {
|
|
if (!mi.hasBody) {
|
|
return false;
|
|
}
|
|
if (mi.hasExceptions() && !compilerEnableExceptions.value) {
|
|
return false;
|
|
} else if (mi.code.length > compilerMaximumMethodSize.value) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
Runtime.canCompile = canCompile;
|
|
function shouldCompile(mi) {
|
|
if (!canCompile(mi)) {
|
|
return false;
|
|
}
|
|
if (mi.isClassInitializer || mi.isScriptInitializer) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
Runtime.shouldCompile = shouldCompile;
|
|
function forceCompile(mi) {
|
|
if (mi.hasExceptions()) {
|
|
return false;
|
|
}
|
|
var holder = mi.holder;
|
|
if (holder instanceof ClassInfo) {
|
|
holder = holder.instanceInfo;
|
|
}
|
|
if (holder instanceof InstanceInfo) {
|
|
var packageName = holder.name.namespaces[0].uri;
|
|
switch (packageName) {
|
|
case 'flash.geom':
|
|
case 'flash.events':
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
var className = holder.name.getOriginalName();
|
|
switch (className) {
|
|
case 'com.google.youtube.model.VideoData':
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
Runtime.forceCompile = forceCompile;
|
|
Runtime.CODE_CACHE = createEmptyObject();
|
|
function searchCodeCache(methodInfo) {
|
|
if (!Runtime.codeCaching.value) {
|
|
return;
|
|
}
|
|
var cacheInfo = Runtime.CODE_CACHE[methodInfo.abc.hash];
|
|
if (!cacheInfo) {
|
|
warn('Cannot Find Code Cache For ABC, name: ' + methodInfo.abc.name + ', hash: ' + methodInfo.abc.hash);
|
|
Counter.count('Code Cache ABC Miss');
|
|
return;
|
|
}
|
|
if (!cacheInfo.isInitialized) {
|
|
methodInfo.abc.scripts.forEach(function (scriptInfo) {
|
|
LazyInitializer.create(scriptInfo).getName();
|
|
});
|
|
methodInfo.abc.classes.forEach(function (classInfo) {
|
|
LazyInitializer.create(classInfo).getName();
|
|
});
|
|
cacheInfo.isInitialized = true;
|
|
}
|
|
var method = cacheInfo.methods[methodInfo.index];
|
|
if (!method) {
|
|
if (methodInfo.isInstanceInitializer || methodInfo.isClassInitializer) {
|
|
Counter.count('Code Cache Query On Initializer');
|
|
} else {
|
|
Counter.count('Code Cache MISS ON OTHER');
|
|
warn('Shouldn\'t MISS: ' + methodInfo + ' ' + methodInfo.debugName);
|
|
}
|
|
Counter.count('Code Cache Miss');
|
|
return;
|
|
}
|
|
log('Linking CC: ' + methodInfo);
|
|
Counter.count('Code Cache Hit');
|
|
return method;
|
|
}
|
|
Runtime.searchCodeCache = searchCodeCache;
|
|
function createInterpretedFunction(methodInfo, scope, hasDynamicScope) {
|
|
var mi = methodInfo;
|
|
var hasDefaults = false;
|
|
var defaults = mi.parameters.map(function (p) {
|
|
if (p.value !== undefined) {
|
|
hasDefaults = true;
|
|
}
|
|
return p.value;
|
|
});
|
|
var fn;
|
|
if (hasDynamicScope) {
|
|
fn = function (scope) {
|
|
var global = this === jsGlobal ? scope.global.object : this;
|
|
var args = sliceArguments(arguments, 1);
|
|
if (hasDefaults && args.length < defaults.length) {
|
|
args = args.concat(defaults.slice(args.length - defaults.length));
|
|
}
|
|
return Shumway.AVM2.Interpreter.interpretMethod(global, methodInfo, scope, args);
|
|
};
|
|
} else {
|
|
fn = function () {
|
|
var global = this === jsGlobal ? scope.global.object : this;
|
|
var args = sliceArguments(arguments);
|
|
if (hasDefaults && args.length < defaults.length) {
|
|
args = args.concat(defaults.slice(arguments.length - defaults.length));
|
|
}
|
|
return Shumway.AVM2.Interpreter.interpretMethod(global, methodInfo, scope, args);
|
|
};
|
|
}
|
|
fn.instanceConstructor = fn;
|
|
fn.debugName = 'Interpreter Function #' + vmNextInterpreterFunctionId++;
|
|
return fn;
|
|
}
|
|
Runtime.createInterpretedFunction = createInterpretedFunction;
|
|
function debugName(value) {
|
|
if (Shumway.isFunction(value)) {
|
|
return value.debugName;
|
|
}
|
|
return value;
|
|
}
|
|
Runtime.debugName = debugName;
|
|
function createCompiledFunction(methodInfo, scope, hasDynamicScope, breakpoint, deferCompilation) {
|
|
var mi = methodInfo;
|
|
var cached = searchCodeCache(mi);
|
|
if (!cached) {
|
|
var result = Compiler.compileMethod(mi, scope, hasDynamicScope);
|
|
var parameters = result.parameters;
|
|
var body = result.body;
|
|
}
|
|
var fnName = mi.name ? Multiname.getQualifiedName(mi.name) : 'fn' + compiledFunctionCount;
|
|
if (mi.holder) {
|
|
var fnNamePrefix = '';
|
|
if (mi.holder instanceof ClassInfo) {
|
|
fnNamePrefix = 'static$' + mi.holder.instanceInfo.name.getName();
|
|
} else if (mi.holder instanceof InstanceInfo) {
|
|
fnNamePrefix = mi.holder.name.getName();
|
|
} else if (mi.holder instanceof ScriptInfo) {
|
|
fnNamePrefix = 'script';
|
|
}
|
|
fnName = fnNamePrefix + '$' + fnName;
|
|
}
|
|
fnName = Shumway.StringUtilities.escapeString(fnName);
|
|
if (mi.verified) {
|
|
fnName += '$V';
|
|
}
|
|
if (compiledFunctionCount == functionBreak.value || breakpoint) {
|
|
body = '{ debugger; \n' + body + '}';
|
|
}
|
|
if (!cached) {
|
|
var fnSource = 'function ' + fnName + ' (' + parameters.join(', ') + ') ' + body;
|
|
}
|
|
if (traceLevel.value > 1) {
|
|
mi.trace(new IndentingWriter(), mi.abc);
|
|
}
|
|
mi.debugTrace = function () {
|
|
mi.trace(new IndentingWriter(), mi.abc);
|
|
};
|
|
if (traceLevel.value > 0) {
|
|
log(fnSource);
|
|
}
|
|
var fn = cached || new Function('return ' + fnSource)();
|
|
fn.debugName = 'Compiled Function #' + vmNextCompiledFunctionId++;
|
|
return fn;
|
|
}
|
|
Runtime.createCompiledFunction = createCompiledFunction;
|
|
function createFunction(mi, scope, hasDynamicScope, breakpoint) {
|
|
if (typeof breakpoint === 'undefined') {
|
|
breakpoint = false;
|
|
}
|
|
true;
|
|
if (mi.freeMethod) {
|
|
if (hasDynamicScope) {
|
|
return Shumway.AVM2.Runtime.bindFreeMethodScope(mi, scope);
|
|
}
|
|
return mi.freeMethod;
|
|
}
|
|
var fn;
|
|
if (fn = Shumway.AVM2.Runtime.checkMethodOverrides(mi)) {
|
|
true;
|
|
return fn;
|
|
}
|
|
ensureFunctionIsInitialized(mi);
|
|
totalFunctionCount++;
|
|
var useInterpreter = false;
|
|
if ((mi.abc.applicationDomain.mode === 1 || !shouldCompile(mi)) && !forceCompile(mi)) {
|
|
useInterpreter = true;
|
|
}
|
|
if (compileOnly.value >= 0) {
|
|
if (Number(compileOnly.value) !== totalFunctionCount) {
|
|
log('Compile Only Skipping ' + totalFunctionCount);
|
|
useInterpreter = true;
|
|
}
|
|
}
|
|
if (compileUntil.value >= 0) {
|
|
if (totalFunctionCount > 1000) {
|
|
log(Shumway.Debug.backtrace());
|
|
log(Shumway.AVM2.Runtime.AVM2.getStackTrace());
|
|
}
|
|
if (totalFunctionCount > compileUntil.value) {
|
|
log('Compile Until Skipping ' + totalFunctionCount);
|
|
useInterpreter = true;
|
|
}
|
|
}
|
|
if (useInterpreter) {
|
|
mi.freeMethod = createInterpretedFunction(mi, scope, hasDynamicScope);
|
|
} else {
|
|
compiledFunctionCount++;
|
|
if (compileOnly.value >= 0 || compileUntil.value >= 0) {
|
|
log('Compiling ' + totalFunctionCount);
|
|
}
|
|
mi.freeMethod = createCompiledFunction(mi, scope, hasDynamicScope, breakpoint, mi.isInstanceInitializer);
|
|
}
|
|
mi.freeMethod.methodInfo = mi;
|
|
if (hasDynamicScope) {
|
|
return Shumway.AVM2.Runtime.bindFreeMethodScope(mi, scope);
|
|
}
|
|
return mi.freeMethod;
|
|
}
|
|
Runtime.createFunction = createFunction;
|
|
function ensureFunctionIsInitialized(methodInfo) {
|
|
var mi = methodInfo;
|
|
if (!mi.analysis) {
|
|
mi.analysis = new Analysis(mi);
|
|
if (mi.needsActivation()) {
|
|
mi.activationPrototype = new ActivationInfo(mi);
|
|
new Shumway.AVM2.Runtime.ActivationBindings(mi).applyTo(mi.abc.applicationDomain, mi.activationPrototype);
|
|
}
|
|
var exceptions = mi.exceptions;
|
|
for (var i = 0, j = exceptions.length; i < j; i++) {
|
|
var handler = exceptions[i];
|
|
if (handler.varName) {
|
|
var varTrait = Object.create(Trait.prototype);
|
|
varTrait.kind = 0;
|
|
varTrait.name = handler.varName;
|
|
varTrait.typeName = handler.typeName;
|
|
varTrait.holder = mi;
|
|
handler.scopeObject = new CatchScopeObject(mi.abc.applicationDomain, varTrait);
|
|
} else {
|
|
handler.scopeObject = new CatchScopeObject(undefined, undefined);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Runtime.ensureFunctionIsInitialized = ensureFunctionIsInitialized;
|
|
function getTraitFunction(trait, scope, natives) {
|
|
true;
|
|
true;
|
|
var mi = trait.methodInfo;
|
|
var fn;
|
|
if (mi.isNative()) {
|
|
var md = trait.metadata;
|
|
if (md && md.native) {
|
|
var nativeName = md.native.value[0].value;
|
|
var makeNativeFunction = getNative(nativeName);
|
|
fn = makeNativeFunction && makeNativeFunction(null, scope);
|
|
} else if (md && md.unsafeJSNative) {
|
|
fn = getNative(md.unsafeJSNative.value[0].value);
|
|
} else if (natives) {
|
|
var k = Multiname.getName(mi.name);
|
|
if (trait.isGetter()) {
|
|
fn = natives[k] ? natives[k].get : undefined;
|
|
} else if (trait.isSetter()) {
|
|
fn = natives[k] ? natives[k].set : undefined;
|
|
} else {
|
|
fn = natives[k];
|
|
}
|
|
}
|
|
if (!fn) {
|
|
Shumway.Debug.warning('No native method for: ' + trait.kindName() + ' ' + mi.holder.name + '::' + Multiname.getQualifiedName(mi.name));
|
|
return function (mi) {
|
|
return function () {
|
|
Shumway.Debug.warning('Calling undefined native method: ' + trait.kindName() + ' ' + mi.holder.name + '::' + Multiname.getQualifiedName(mi.name));
|
|
};
|
|
}(mi);
|
|
}
|
|
} else {
|
|
if (Runtime.traceExecution.value >= 2) {
|
|
log('Creating Function For Trait: ' + trait.holder + ' ' + trait);
|
|
}
|
|
fn = createFunction(mi, scope, false, false);
|
|
true;
|
|
}
|
|
if (Runtime.traceExecution.value >= 3) {
|
|
log('Made Function: ' + Multiname.getQualifiedName(mi.name));
|
|
}
|
|
return fn;
|
|
}
|
|
Runtime.getTraitFunction = getTraitFunction;
|
|
function createClass(classInfo, baseClass, scope) {
|
|
true;
|
|
var ci = classInfo;
|
|
var ii = ci.instanceInfo;
|
|
var domain = ci.abc.applicationDomain;
|
|
var className = Multiname.getName(ii.name);
|
|
if (Runtime.traceExecution.value) {
|
|
log('Creating ' + (ii.isInterface() ? 'Interface' : 'Class') + ': ' + className + (ci.native ? ' replaced with native ' + ci.native.cls : ''));
|
|
}
|
|
var cls;
|
|
if (ii.isInterface()) {
|
|
cls = Shumway.AVM2.Runtime.Interface.createInterface(classInfo);
|
|
} else {
|
|
cls = Shumway.AVM2.Runtime.Class.createClass(classInfo, baseClass, scope);
|
|
}
|
|
if (Runtime.traceClasses.value) {
|
|
domain.loadedClasses.push(cls);
|
|
domain.traceLoadedClasses(true);
|
|
}
|
|
if (ii.isInterface()) {
|
|
return cls;
|
|
}
|
|
domain.onMessage.notify1('classCreated', cls);
|
|
if (cls.instanceConstructor && cls !== Shumway.AVM2.Runtime.Class) {
|
|
cls.verify();
|
|
}
|
|
if (baseClass && (Multiname.getQualifiedName(baseClass.classInfo.instanceInfo.name.name) === 'Proxy' || baseClass.isProxy)) {
|
|
installProxyClassWrapper(cls);
|
|
cls.isProxy = true;
|
|
}
|
|
classInfo.classObject = cls;
|
|
createFunction(classInfo.init, scope, false, false).call(cls);
|
|
if (Runtime.sealConstTraits) {
|
|
this.sealConstantTraits(cls, ci.traits);
|
|
}
|
|
return cls;
|
|
}
|
|
Runtime.createClass = createClass;
|
|
function sealConstantTraits(object, traits) {
|
|
for (var i = 0, j = traits.length; i < j; i++) {
|
|
var trait = traits[i];
|
|
if (trait.isConst()) {
|
|
var qn = Multiname.getQualifiedName(trait.name);
|
|
var value = object[qn];
|
|
(function (qn, value) {
|
|
Object.defineProperty(object, qn, {
|
|
configurable: false,
|
|
enumerable: false,
|
|
get: function () {
|
|
return value;
|
|
},
|
|
set: function () {
|
|
throwErrorFromVM(Shumway.AVM2.Runtime.AVM2.currentDomain(), 'ReferenceError', 'Illegal write to read-only property ' + qn + '.', 0);
|
|
}
|
|
});
|
|
}(qn, value));
|
|
}
|
|
}
|
|
}
|
|
Runtime.sealConstantTraits = sealConstantTraits;
|
|
function applyType(domain, factory, types) {
|
|
var factoryClassName = factory.classInfo.instanceInfo.name.name;
|
|
if (factoryClassName === 'Vector') {
|
|
true;
|
|
var type = types[0];
|
|
var typeClassName;
|
|
if (!Shumway.isNullOrUndefined(type)) {
|
|
typeClassName = type.classInfo.instanceInfo.name.name.toLowerCase();
|
|
switch (typeClassName) {
|
|
case 'int':
|
|
case 'uint':
|
|
case 'double':
|
|
case 'object':
|
|
return domain.getClass('packageInternal __AS3__.vec.Vector$' + typeClassName);
|
|
}
|
|
}
|
|
return domain.getClass('packageInternal __AS3__.vec.Vector$object').applyType(type);
|
|
} else {
|
|
return Shumway.Debug.notImplemented(factoryClassName);
|
|
}
|
|
}
|
|
Runtime.applyType = applyType;
|
|
}(AVM2.Runtime || (AVM2.Runtime = {})));
|
|
var Runtime = AVM2.Runtime;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
var CC = Shumway.AVM2.Runtime.CODE_CACHE;
|
|
var VM_LENGTH = Shumway.AVM2.Runtime.VM_LENGTH;
|
|
var VM_IS_PROXY = Shumway.AVM2.Runtime.VM_IS_PROXY;
|
|
var VM_CALL_PROXY = Shumway.AVM2.Runtime.VM_CALL_PROXY;
|
|
var VM_NATIVE_BUILTIN_ORIGINALS = Shumway.AVM2.Runtime.VM_NATIVE_BUILTIN_ORIGINALS;
|
|
var VM_OPEN_METHOD_PREFIX = 'm';
|
|
var VM_OPEN_SET_METHOD_PREFIX = 's';
|
|
var VM_OPEN_GET_METHOD_PREFIX = 'g';
|
|
var SAVED_SCOPE_NAME = '$SS';
|
|
var originalStringReplace = String.prototype.replace;
|
|
XRegExp.install({
|
|
natives: true
|
|
});
|
|
var callWriter = new IndentingWriter(false, function (str) {
|
|
print(str);
|
|
});
|
|
var objectIDs = 0;
|
|
var OBJECT_NAME = 'Object Name';
|
|
function objectConstantName(object) {
|
|
true;
|
|
if (object.hasOwnProperty(OBJECT_NAME)) {
|
|
return object[OBJECT_NAME];
|
|
}
|
|
if (object instanceof LazyInitializer) {
|
|
return object.getName();
|
|
}
|
|
var name, id = objectIDs++;
|
|
if (object instanceof Global) {
|
|
name = '$G' + id;
|
|
} else if (object instanceof Multiname) {
|
|
name = '$M' + id;
|
|
} else if (isClass(object)) {
|
|
name = '$C' + id;
|
|
} else {
|
|
name = '$O' + id;
|
|
}
|
|
Object.defineProperty(object, OBJECT_NAME, {
|
|
value: name,
|
|
writable: false,
|
|
enumerable: false
|
|
});
|
|
jsGlobal[name] = object;
|
|
return name;
|
|
}
|
|
var isClass = Shumway.AVM2.Runtime.isClass;
|
|
var isTrampoline = Shumway.AVM2.Runtime.isTrampoline;
|
|
var isMemoizer = Shumway.AVM2.Runtime.isMemoizer;
|
|
var LazyInitializer = Shumway.AVM2.Runtime.LazyInitializer;
|
|
var getNamespaceResolutionMap = Shumway.AVM2.Runtime.getNamespaceResolutionMap;
|
|
var resolveMultinameProperty = Shumway.AVM2.Runtime.resolveMultinameProperty;
|
|
var asGetPublicProperty = Shumway.AVM2.Runtime.asGetPublicProperty;
|
|
var asGetProperty = Shumway.AVM2.Runtime.asGetProperty;
|
|
var asGetPropertyLikelyNumeric = Shumway.AVM2.Runtime.asGetPropertyLikelyNumeric;
|
|
var asGetResolvedStringProperty = Shumway.AVM2.Runtime.asGetResolvedStringProperty;
|
|
var asCallResolvedStringProperty = Shumway.AVM2.Runtime.asCallResolvedStringProperty;
|
|
var asGetResolvedStringPropertyFallback = Shumway.AVM2.Runtime.asGetResolvedStringPropertyFallback;
|
|
var asSetPublicProperty = Shumway.AVM2.Runtime.asSetPublicProperty;
|
|
var asSetProperty = Shumway.AVM2.Runtime.asSetProperty;
|
|
var asSetPropertyLikelyNumeric = Shumway.AVM2.Runtime.asSetPropertyLikelyNumeric;
|
|
var asDefinePublicProperty = Shumway.AVM2.Runtime.asDefinePublicProperty;
|
|
var asDefineProperty = Shumway.AVM2.Runtime.asDefineProperty;
|
|
var asCallPublicProperty = Shumway.AVM2.Runtime.asCallPublicProperty;
|
|
var asCallProperty = Shumway.AVM2.Runtime.asCallProperty;
|
|
var asCallSuper = Shumway.AVM2.Runtime.asCallSuper;
|
|
var asSetSuper = Shumway.AVM2.Runtime.asSetSuper;
|
|
var asGetSuper = Shumway.AVM2.Runtime.asGetSuper;
|
|
var construct = Shumway.AVM2.Runtime.construct;
|
|
var asConstructProperty = Shumway.AVM2.Runtime.asConstructProperty;
|
|
var asHasProperty = Shumway.AVM2.Runtime.asHasProperty;
|
|
var asDeleteProperty = Shumway.AVM2.Runtime.asDeleteProperty;
|
|
var asGetNumericProperty = Shumway.AVM2.Runtime.asGetNumericProperty;
|
|
var asSetNumericProperty = Shumway.AVM2.Runtime.asSetNumericProperty;
|
|
var asGetDescendants = Shumway.AVM2.Runtime.asGetDescendants;
|
|
var asNextNameIndex = Shumway.AVM2.Runtime.asNextNameIndex;
|
|
var asNextName = Shumway.AVM2.Runtime.asNextName;
|
|
var asNextValue = Shumway.AVM2.Runtime.asNextValue;
|
|
var asGetEnumerableKeys = Shumway.AVM2.Runtime.asGetEnumerableKeys;
|
|
var initializeGlobalObject = Shumway.AVM2.Runtime.initializeGlobalObject;
|
|
initializeGlobalObject(jsGlobal);
|
|
var asTypeOf = Shumway.AVM2.Runtime.asTypeOf;
|
|
var publicizeProperties = Shumway.AVM2.Runtime.publicizeProperties;
|
|
var asGetSlot = Shumway.AVM2.Runtime.asGetSlot;
|
|
var asSetSlot = Shumway.AVM2.Runtime.asSetSlot;
|
|
var asHasNext2 = Shumway.AVM2.Runtime.asHasNext2;
|
|
var getDescendants = Shumway.AVM2.Runtime.getDescendants;
|
|
var checkFilter = Shumway.AVM2.Runtime.checkFilter;
|
|
var ActivationInfo = Shumway.AVM2.Runtime.ActivationInfo;
|
|
var ScopeStack = Shumway.AVM2.Runtime.ScopeStack;
|
|
var Scope = Shumway.AVM2.Runtime.Scope;
|
|
var bindFreeMethodScope = Shumway.AVM2.Runtime.bindFreeMethodScope;
|
|
var nameInTraits = Shumway.AVM2.Runtime.nameInTraits;
|
|
function resolveMultiname(object, mn, traitsOnly) {
|
|
return object.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags);
|
|
}
|
|
var sliceArguments = Shumway.AVM2.Runtime.sliceArguments;
|
|
var nonProxyingHasProperty = Shumway.AVM2.Runtime.nonProxyingHasProperty;
|
|
var forEachPublicProperty = Shumway.AVM2.Runtime.forEachPublicProperty;
|
|
var wrapJSObject = Shumway.AVM2.Runtime.wrapJSObject;
|
|
var asCreateActivation = Shumway.AVM2.Runtime.asCreateActivation;
|
|
var CatchScopeObject = Shumway.AVM2.Runtime.CatchScopeObject;
|
|
var Global = Shumway.AVM2.Runtime.Global;
|
|
var canCompile = Shumway.AVM2.Runtime.canCompile;
|
|
var shouldCompile = Shumway.AVM2.Runtime.shouldCompile;
|
|
var forceCompile = Shumway.AVM2.Runtime.forceCompile;
|
|
var createInterpretedFunction = Shumway.AVM2.Runtime.createInterpretedFunction;
|
|
var debugName = Shumway.AVM2.Runtime.debugName;
|
|
var createCompiledFunction = Shumway.AVM2.Runtime.createCompiledFunction;
|
|
var getMethodOverrideKey = Shumway.AVM2.Runtime.getMethodOverrideKey;
|
|
var checkMethodOverrides = Shumway.AVM2.Runtime.checkMethodOverrides;
|
|
var makeTrampoline = Shumway.AVM2.Runtime.makeTrampoline;
|
|
var makeMemoizer = Shumway.AVM2.Runtime.makeMemoizer;
|
|
var createFunction = Shumway.AVM2.Runtime.createFunction;
|
|
var ensureFunctionIsInitialized = Shumway.AVM2.Runtime.ensureFunctionIsInitialized;
|
|
var getTraitFunction = Shumway.AVM2.Runtime.getTraitFunction;
|
|
var createClass = Shumway.AVM2.Runtime.createClass;
|
|
var sealConstantTraits = Shumway.AVM2.Runtime.sealConstantTraits;
|
|
var applyType = Shumway.AVM2.Runtime.applyType;
|
|
var throwError = Shumway.AVM2.Runtime.throwError;
|
|
var throwErrorFromVM = Shumway.AVM2.Runtime.throwErrorFromVM;
|
|
var translateError = Shumway.AVM2.Runtime.translateError;
|
|
var asIsInstanceOf = Shumway.AVM2.Runtime.asIsInstanceOf;
|
|
var asIsType = Shumway.AVM2.Runtime.asIsType;
|
|
var asAsType = Shumway.AVM2.Runtime.asAsType;
|
|
var asCoerceByMultiname = Shumway.AVM2.Runtime.asCoerceByMultiname;
|
|
var asCoerce = Shumway.AVM2.Runtime.asCoerce;
|
|
var asCoerceString = Shumway.AVM2.Runtime.asCoerceString;
|
|
var asCoerceInt = Shumway.AVM2.Runtime.asCoerceInt;
|
|
var asCoerceUint = Shumway.AVM2.Runtime.asCoerceUint;
|
|
var asCoerceNumber = Shumway.AVM2.Runtime.asCoerceNumber;
|
|
var asCoerceBoolean = Shumway.AVM2.Runtime.asCoerceBoolean;
|
|
var asCoerceObject = Shumway.AVM2.Runtime.asCoerceObject;
|
|
var asDefaultCompareFunction = Shumway.AVM2.Runtime.asDefaultCompareFunction;
|
|
var asCompare = Shumway.AVM2.Runtime.asCompare;
|
|
var asAdd = Shumway.AVM2.Runtime.asAdd;
|
|
var GlobalMultinameResolver = Shumway.AVM2.Runtime.GlobalMultinameResolver;
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
(function (Runtime) {
|
|
Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['static mochi.as3.MochiServices::connect'] = function () {
|
|
return;
|
|
};
|
|
Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['static MochiBot::track'] = function () {
|
|
return;
|
|
};
|
|
Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['com.midasplayer.debug.DebugLog::trace'] = function (msg) {
|
|
log(msg);
|
|
};
|
|
Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['com.midasplayer.engine.comm.DebugGameComm::getGameData'] = function () {
|
|
return '<gamedata randomseed="554884453" version="1">\n<musicOn>true</musicOn>\n<soundOn>true</soundOn>\n<isShortGame>false</isShortGame>\n<booster_1>0</booster_1>\n<booster_2>0</booster_2>\n<booster_3>0</booster_3>\n<booster_4>0</booster_4>\n<booster_5>0</booster_5>\n<bestScore>0</bestScore>\n<bestChain>0</bestChain>\n<bestLevel>0</bestLevel>\n<bestCrushed>0</bestCrushed>\n<bestMixed>0</bestMixed>\n<text id="outro.crushed">Candy crushed</text>\n<text id="outro.bestever">best ever</text>\n<text id="outro.trophy.two">scored {0} in one game</text>\n<text id="outro.combo_color_color">All Clear Created</text>\n<text id="outro.trophy.one">crushed {0} candy in one game</text>\n<text id="outro.score">Score</text>\n<text id="outro.opengame">Please register to play the full game</text>\n<text id="outro.chain">Longest chain</text>\n<text id="outro.time">Game ends in {0} seconds</text>\n<text id="outro.combo_color_line">Super Stripes Created</text>\n<text id="game.nomoves">No more moves!</text>\n<text id="outro.combo_wrapper_line">Mega-Candy Created</text>\n<text id="intro.time">Game starts in {0} seconds</text>\n<text id="outro.now">now</text>\n<text id="outro.level">Level reached</text>\n<text id="outro.title">Game Over</text>\n<text id="intro.info1">Match 3 Candy of the same colour to crush them. Matching 4 or 5 in different formations generates special sweets that are extra tasty.</text>\n<text id="intro.info2">You 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: </text>\n<text id="outro.combo_color_wrapper">Double Colour Bombs Created</text>\n<text id="outro.trophy.three">made {0} combined candy in one game</text>\n<text id="intro.title">Play like this:</text>\n</gamedata>';
|
|
};
|
|
Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['com.antkarlov.Preloader::com.antkarlov:Preloader.isUrl'] = function () {
|
|
return true;
|
|
};
|
|
Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['static com.demonsters.debugger.MonsterDebugger::initialize'] = function () {
|
|
};
|
|
Shumway.AVM2.Runtime.VM_METHOD_OVERRIDES['com.spilgames.api.core.tracking.TrackConfig::getTrackers'] = function () {
|
|
return [];
|
|
};
|
|
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 () {
|
|
};
|
|
}(AVM2.Runtime || (AVM2.Runtime = {})));
|
|
var Runtime = AVM2.Runtime;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
var checkArguments = true;
|
|
function asCheckVectorSetNumericProperty(i, length, fixed) {
|
|
if (i < 0 || i > length || i === length && fixed || !isNumeric(i)) {
|
|
throwError('RangeError', Errors.OutOfRangeError, i, length);
|
|
}
|
|
}
|
|
function asCheckVectorGetNumericProperty(i, length) {
|
|
if (i < 0 || i >= length || !isNumeric(i)) {
|
|
throwError('RangeError', Errors.OutOfRangeError, i, length);
|
|
}
|
|
}
|
|
var TypedArrayVector = function () {
|
|
var EXTRA_CAPACITY = 4;
|
|
var INITIAL_CAPACITY = 10;
|
|
var DEFAULT_VALUE = 0;
|
|
function vector(length, fixed) {
|
|
length = length | 0;
|
|
this._fixed = !(!fixed);
|
|
this._buffer = new Int32Array(Math.max(INITIAL_CAPACITY, length + EXTRA_CAPACITY));
|
|
this._offset = 0;
|
|
this._length = length;
|
|
}
|
|
vector.callable = function (object) {
|
|
if (object instanceof vector) {
|
|
return object;
|
|
}
|
|
var length = object.asGetProperty(undefined, 'length');
|
|
if (length !== undefined) {
|
|
var v = new vector(length, false);
|
|
for (var i = 0; i < length; i++) {
|
|
v.asSetNumericProperty(i, object.asGetPublicProperty(i));
|
|
}
|
|
return v;
|
|
}
|
|
unexpected();
|
|
};
|
|
vector.prototype.internalToString = function () {
|
|
var str = '';
|
|
var start = this._offset;
|
|
var end = start + this._length;
|
|
for (var i = 0; i < this._buffer.length; i++) {
|
|
if (i === start) {
|
|
str += '[';
|
|
}
|
|
if (i === end) {
|
|
str += ']';
|
|
}
|
|
str += this._buffer[i];
|
|
if (i < this._buffer.length - 1) {
|
|
str += ',';
|
|
}
|
|
}
|
|
if (this._offset + this._length === this._buffer.length) {
|
|
str += ']';
|
|
}
|
|
return str + ': offset: ' + this._offset + ', length: ' + this._length + ', capacity: ' + this._buffer.length;
|
|
};
|
|
vector.prototype.toString = function () {
|
|
var str = '';
|
|
for (var i = 0; i < this._length; i++) {
|
|
str += this._buffer[this._offset + i];
|
|
if (i < this._length - 1) {
|
|
str += ',';
|
|
}
|
|
}
|
|
return str;
|
|
};
|
|
vector.prototype._view = function () {
|
|
return this._buffer.subarray(this._offset, this._offset + this._length);
|
|
};
|
|
vector.prototype._ensureCapacity = function (length) {
|
|
var minCapacity = this._offset + length;
|
|
if (minCapacity < this._buffer.length) {
|
|
return;
|
|
}
|
|
if (length <= this._buffer.length) {
|
|
var offset = this._buffer.length - length >> 2;
|
|
this._buffer.set(this._view(), offset);
|
|
this._offset = offset;
|
|
return;
|
|
}
|
|
var oldCapacity = this._buffer.length;
|
|
var newCapacity = oldCapacity * 3 >> 2;
|
|
if (newCapacity < minCapacity) {
|
|
newCapacity = minCapacity;
|
|
}
|
|
var buffer = new Int32Array(newCapacity);
|
|
buffer.set(this._buffer, 0);
|
|
this._buffer = buffer;
|
|
};
|
|
vector.prototype.concat = function () {
|
|
notImplemented('TypedArrayVector.concat');
|
|
};
|
|
vector.prototype.every = function (callback, thisObject) {
|
|
for (var i = 0; i < this._length; i++) {
|
|
if (!callback.call(thisObject, this.asGetNumericProperty(i), i, this)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
vector.prototype.filter = function (callback, thisObject) {
|
|
var v = new vector();
|
|
for (var i = 0; i < this._length; i++) {
|
|
if (callback.call(thisObject, this.asGetNumericProperty(i), i, this)) {
|
|
v.push(this.asGetNumericProperty(i));
|
|
}
|
|
}
|
|
return v;
|
|
};
|
|
vector.prototype.some = function (callback, thisObject) {
|
|
if (arguments.length !== 2) {
|
|
throwError('ArgumentError', Errors.WrongArgumentCountError);
|
|
} else if (!isFunction(callback)) {
|
|
throwError('ArgumentError', Errors.CheckTypeFailedError);
|
|
}
|
|
for (var i = 0; i < this._length; i++) {
|
|
if (callback.call(thisObject, this.asGetNumericProperty(i), i, this)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
vector.prototype.forEach = function (callback, thisObject) {
|
|
for (var i = 0; i < this._length; i++) {
|
|
callback.call(thisObject, this.asGetNumericProperty(i), i, this);
|
|
}
|
|
};
|
|
vector.prototype.join = function (sep) {
|
|
notImplemented('TypedArrayVector.join');
|
|
};
|
|
vector.prototype.indexOf = function (searchElement, fromIndex) {
|
|
notImplemented('TypedArrayVector.indexOf');
|
|
};
|
|
vector.prototype.lastIndexOf = function (searchElement, fromIndex) {
|
|
notImplemented('TypedArrayVector.lastIndexOf');
|
|
};
|
|
vector.prototype.map = function (callback, thisObject) {
|
|
if (!isFunction(callback)) {
|
|
throwError('ArgumentError', Errors.CheckTypeFailedError);
|
|
}
|
|
var v = new vector();
|
|
for (var i = 0; i < this._length; i++) {
|
|
v.push(callback.call(thisObject, this.asGetNumericProperty(i), i, this));
|
|
}
|
|
return v;
|
|
};
|
|
vector.prototype.push = function () {
|
|
this._checkFixed();
|
|
this._ensureCapacity(this._length + arguments.length);
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
this._buffer[this._offset + this._length++] = arguments[i];
|
|
}
|
|
};
|
|
vector.prototype.pop = function () {
|
|
this._checkFixed();
|
|
if (this._length === 0) {
|
|
return DEFAULT_VALUE;
|
|
}
|
|
this._length--;
|
|
return this._buffer[this._offset + this._length];
|
|
};
|
|
vector.prototype.reverse = function () {
|
|
var l = this._offset;
|
|
var r = this._offset + this._length - 1;
|
|
var b = this._buffer;
|
|
while (l < r) {
|
|
var t = b[l];
|
|
b[l] = b[r];
|
|
b[r] = t;
|
|
l++;
|
|
r--;
|
|
}
|
|
};
|
|
vector.CASEINSENSITIVE = 1;
|
|
vector.DESCENDING = 2;
|
|
vector.UNIQUESORT = 4;
|
|
vector.RETURNINDEXEDARRAY = 8;
|
|
vector.NUMERIC = 16;
|
|
function defaultCompareFunction(a, b) {
|
|
return String(a).localeCompare(String(b));
|
|
}
|
|
function compare(a, b, options, compareFunction) {
|
|
assertNotImplemented(!(options & vector.CASEINSENSITIVE), 'CASEINSENSITIVE');
|
|
assertNotImplemented(!(options & vector.UNIQUESORT), 'UNIQUESORT');
|
|
assertNotImplemented(!(options & vector.RETURNINDEXEDARRAY), 'RETURNINDEXEDARRAY');
|
|
var result = 0;
|
|
if (!compareFunction) {
|
|
compareFunction = defaultCompareFunction;
|
|
}
|
|
if (options & vector.NUMERIC) {
|
|
a = toNumber(a);
|
|
b = toNumber(b);
|
|
result = a < b ? -1 : a > b ? 1 : 0;
|
|
} else {
|
|
result = compareFunction(a, b);
|
|
}
|
|
if (options & vector.DESCENDING) {
|
|
result *= -1;
|
|
}
|
|
return result;
|
|
}
|
|
function _sort(a) {
|
|
var stack = [];
|
|
var sp = -1;
|
|
var l = 0;
|
|
var r = a.length - 1;
|
|
var i, j, swap, temp;
|
|
while (true) {
|
|
if (r - l <= 100) {
|
|
for (j = l + 1; j <= r; j++) {
|
|
swap = a[j];
|
|
i = j - 1;
|
|
while (i >= l && a[i] > swap) {
|
|
a[i + 1] = a[i--];
|
|
}
|
|
a[i + 1] = swap;
|
|
}
|
|
if (sp == -1) {
|
|
break;
|
|
}
|
|
r = stack[sp--];
|
|
l = stack[sp--];
|
|
} else {
|
|
var median = l + r >> 1;
|
|
i = l + 1;
|
|
j = r;
|
|
swap = a[median];
|
|
a[median] = a[i];
|
|
a[i] = swap;
|
|
if (a[l] > a[r]) {
|
|
swap = a[l];
|
|
a[l] = a[r];
|
|
a[r] = swap;
|
|
}
|
|
if (a[i] > a[r]) {
|
|
swap = a[i];
|
|
a[i] = a[r];
|
|
a[r] = swap;
|
|
}
|
|
if (a[l] > a[i]) {
|
|
swap = a[l];
|
|
a[l] = a[i];
|
|
a[i] = swap;
|
|
}
|
|
temp = a[i];
|
|
while (true) {
|
|
do {
|
|
i++;
|
|
} while (a[i] < temp);
|
|
do {
|
|
j--;
|
|
} while (a[j] > temp);
|
|
if (j < i) {
|
|
break;
|
|
}
|
|
swap = a[i];
|
|
a[i] = a[j];
|
|
a[j] = swap;
|
|
}
|
|
a[l + 1] = a[j];
|
|
a[j] = temp;
|
|
if (r - i + 1 >= j - l) {
|
|
stack[++sp] = i;
|
|
stack[++sp] = r;
|
|
r = j - 1;
|
|
} else {
|
|
stack[++sp] = l;
|
|
stack[++sp] = j - 1;
|
|
l = i;
|
|
}
|
|
}
|
|
}
|
|
return a;
|
|
}
|
|
vector.prototype._sortNumeric = function (descending) {
|
|
_sort(this._view());
|
|
if (descending) {
|
|
this.reverse();
|
|
}
|
|
};
|
|
vector.prototype.sort = function () {
|
|
if (arguments.length === 0) {
|
|
return Array.prototype.sort.call(this._view());
|
|
}
|
|
var compareFunction, options = 0;
|
|
if (arguments[0] instanceof Function) {
|
|
compareFunction = arguments[0];
|
|
} else if (isNumber(arguments[0])) {
|
|
options = arguments[0];
|
|
}
|
|
if (isNumber(arguments[1])) {
|
|
options = arguments[1];
|
|
}
|
|
if (options & TypedArrayVector.NUMERIC) {
|
|
return this._sortNumeric(options & vector.DESCENDING);
|
|
}
|
|
Array.prototype.sort.call(this._view(), function (a, b) {
|
|
return compare(a, b, options, compareFunction);
|
|
});
|
|
};
|
|
vector.prototype.asGetNumericProperty = function (i) {
|
|
checkArguments && asCheckVectorGetNumericProperty(i, this._length);
|
|
return this._buffer[this._offset + i];
|
|
};
|
|
vector.prototype.asSetNumericProperty = function (i, v) {
|
|
checkArguments && asCheckVectorSetNumericProperty(i, this._length, this._fixed);
|
|
if (i === this._length) {
|
|
this._ensureCapacity(this._length + 1);
|
|
this._length++;
|
|
}
|
|
this._buffer[this._offset + i] = v;
|
|
};
|
|
vector.prototype.shift = function () {
|
|
this._checkFixed();
|
|
if (this._length === 0) {
|
|
return 0;
|
|
}
|
|
this._length--;
|
|
return this._buffer[this._offset++];
|
|
};
|
|
vector.prototype._checkFixed = function () {
|
|
if (this._fixed) {
|
|
throwError('RangeError', Errors.VectorFixedError);
|
|
}
|
|
};
|
|
vector.prototype._slide = function (distance) {
|
|
this._buffer.set(this._view(), this._offset + distance);
|
|
this._offset += distance;
|
|
};
|
|
vector.prototype.unshift = function () {
|
|
this._checkFixed();
|
|
if (!arguments.length) {
|
|
return;
|
|
}
|
|
this._ensureCapacity(this._length + arguments.length);
|
|
this._slide(arguments.length);
|
|
this._offset -= arguments.length;
|
|
this._length += arguments.length;
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
this._buffer[this._offset + i] = arguments[i];
|
|
}
|
|
};
|
|
vector.prototype.asGetEnumerableKeys = function () {
|
|
if (vector.prototype === this) {
|
|
return Object.prototype.asGetEnumerableKeys.call(this);
|
|
}
|
|
var keys = [];
|
|
for (var i = 0; i < this._length; i++) {
|
|
keys.push(i);
|
|
}
|
|
return keys;
|
|
};
|
|
vector.prototype.asHasProperty = function (namespaces, name, flags) {
|
|
if (vector.prototype === this || !isNumeric(name)) {
|
|
return Object.prototype.asHasProperty.call(this, namespaces, name, flags);
|
|
}
|
|
var index = toNumber(name);
|
|
return index >= 0 && index < this._length;
|
|
};
|
|
Object.defineProperty(vector.prototype, 'length', {
|
|
get: function () {
|
|
return this._length;
|
|
},
|
|
set: function (length) {
|
|
length = length >>> 0;
|
|
if (length > this._length) {
|
|
this._ensureCapacity(length);
|
|
for (var i = this._offset + this._length, j = this._offset + length; i < j; i++) {
|
|
this._buffer[i] = DEFAULT_VALUE;
|
|
}
|
|
}
|
|
this._length = length;
|
|
}
|
|
});
|
|
vector.prototype._spliceHelper = function (index, insertCount, deleteCount, args, offset) {
|
|
insertCount = clamp(insertCount, 0, args.length - offset);
|
|
deleteCount = clamp(deleteCount, 0, this._length - index);
|
|
this._ensureCapacity(this._length - deleteCount + insertCount);
|
|
var right = this._offset + index + deleteCount;
|
|
var slice = this._buffer.subarray(right, right + this._length - index - deleteCount);
|
|
this._buffer.set(slice, this._offset + index + insertCount);
|
|
this._length += insertCount - deleteCount;
|
|
for (var i = 0; i < insertCount; i++) {
|
|
this._buffer[this._offset + index + i] = args.asGetNumericProperty(offset + i);
|
|
}
|
|
};
|
|
vector.prototype.asGetEnumerableKeys = function () {
|
|
if (vector.prototype === this) {
|
|
return Object.prototype.asGetEnumerableKeys.call(this);
|
|
}
|
|
var keys = [];
|
|
for (var i = 0; i < this._length; i++) {
|
|
keys.push(i);
|
|
}
|
|
return keys;
|
|
};
|
|
return vector;
|
|
}();
|
|
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<b;d++)c.asSetNumericProperty(d,a.asGetPublicProperty(d));return c}unexpected()}; vector.prototype.internalToString=function(){for(var a="",b=this._offset,c=b+this._length,d=0;d<this._buffer.length;d++)d===b&&(a+="["),d===c&&(a+="]"),a+=this._buffer[d],d<this._buffer.length-1&&(a+=",");this._offset+this._length===this._buffer.length&&(a+="]");return a+": offset: "+this._offset+", length: "+this._length+", capacity: "+this._buffer.length};vector.prototype.toString=function(){for(var a="",b=0;b<this._length;b++)a+=this._buffer[this._offset+b],b<this._length-1&&(a+=",");return a}; vector.prototype._view=function(){return this._buffer.subarray(this._offset,this._offset+this._length)};vector.prototype._ensureCapacity=function(a){var b=this._offset+a;b<this._buffer.length||(a<=this._buffer.length?(b=this._buffer.length-a>>2,this._buffer.set(this._view(),b),this._offset=b):(a=3*this._buffer.length>>2,a<b&&(a=b),b=new Int32Array(a),b.set(this._buffer,0),this._buffer=b))}; vector.prototype.every=function(a,b){for(var c=0;c<this._length;c++)if(!a.call(b,this.asGetNumericProperty(c),c,this))return!1;return!0};vector.prototype.filter=function(a,b){for(var c=new vector,d=0;d<this._length;d++)a.call(b,this.asGetNumericProperty(d),d,this)&&c.push(this.asGetNumericProperty(d));return c}; vector.prototype.some=function(a,b){2!==arguments.length?throwError("ArgumentError",Errors.WrongArgumentCountError):isFunction(a)||throwError("ArgumentError",Errors.CheckTypeFailedError);for(var c=0;c<this._length;c++)if(a.call(b,this.asGetNumericProperty(c),c,this))return!0;return!1};vector.prototype.forEach=function(a,b){for(var c=0;c<this._length;c++)a.call(b,this.asGetNumericProperty(c),c,this)};vector.prototype.join=function(a){notImplemented("TypedArrayVector.join")}; vector.prototype.indexOf=function(a,b){notImplemented("TypedArrayVector.indexOf")};vector.prototype.lastIndexOf=function(a,b){notImplemented("TypedArrayVector.lastIndexOf")};vector.prototype.map=function(a,b){isFunction(a)||throwError("ArgumentError",Errors.CheckTypeFailedError);for(var c=new vector,d=0;d<this._length;d++)c.push(a.call(b,this.asGetNumericProperty(d),d,this));return c}; vector.prototype.push=function(){this._checkFixed();this._ensureCapacity(this._length+arguments.length);for(var a=0;a<arguments.length;a++)this._buffer[this._offset+this._length++]=arguments[a]};vector.prototype.pop=function(){this._checkFixed();if(0===this._length)return DEFAULT_VALUE;this._length--;return this._buffer[this._offset+this._length]};vector.prototype.reverse=function(){for(var a=this._offset,b=this._offset+this._length-1,c=this._buffer;a<b;){var d=c[a];c[a]=c[b];c[b]=d;a++;b--}}; vector.CASEINSENSITIVE=1;vector.DESCENDING=2;vector.UNIQUESORT=4;vector.RETURNINDEXEDARRAY=8;vector.NUMERIC=16;function defaultCompareFunction(a,b){return String(a).localeCompare(String(b))} function compare(a,b,c,d){assertNotImplemented(!(c&vector.CASEINSENSITIVE),"CASEINSENSITIVE");assertNotImplemented(!(c&vector.UNIQUESORT),"UNIQUESORT");assertNotImplemented(!(c&vector.RETURNINDEXEDARRAY),"RETURNINDEXEDARRAY");var f=0;d||(d=defaultCompareFunction);c&vector.NUMERIC?(a=toNumber(a),b=toNumber(b),f=a<b?-1:a>b?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);do g--;while(a[g]>k);if(g<e)break;h=a[e];a[e]=a[g];a[g]=h}a[d+1]=a[g];a[g]=k;f-e+1>=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<arguments.length;a++)this._buffer[this._offset+a]=arguments[a]}}; vector.prototype.asGetEnumerableKeys=function(){if(vector.prototype===this)return Object.prototype.asGetEnumerableKeys.call(this);for(var a=[],b=0;b<this._length;b++)a.push(b);return a};vector.prototype.asHasProperty=function(a,b,c){if(vector.prototype===this||!isNumeric(b))return Object.prototype.asHasProperty.call(this,a,b,c);a=toNumber(b);return 0<=a&&a<this._length}; Object.defineProperty(vector.prototype,"length",{get:function(){return this._length},set:function(a){a>>>=0;if(a>this._length){this._ensureCapacity(a);for(var b=this._offset+this._length,c=this._offset+a;b<c;b++)this._buffer[b]=DEFAULT_VALUE}this._length=a}}); vector.prototype._spliceHelper=function(a,b,c,d,f){debugger;b=clamp(b,0,d.length-f);c=clamp(c,0,this._length-a);this._ensureCapacity(this._length-c+b);var e=this._offset+a+c,e=this._buffer.subarray(e,e+this._length-a-c);this._buffer.set(e,this._offset+a+b);this._length+=b-c;for(c=0;c<b;c++)this._buffer[this._offset+a+c]=d.asGetNumericProperty(f+c)}; vector.prototype.asGetEnumerableKeys=function(){if(vector.prototype===this)return Object.prototype.asGetEnumerableKeys.call(this);for(var a=[],b=0;b<this._length;b++)a.push(b);return a};';
|
|
var Int32Vector = TypedArrayVector;
|
|
var Uint32Vector = new Function(originalStringReplace.call(typedArrayVectorTemplate, /Int32Array/g, 'Uint32Array') + ' return vector;')();
|
|
var Float64Vector = new Function(originalStringReplace.call(typedArrayVectorTemplate, /Int32Array/g, 'Float64Array') + ' return vector;')();
|
|
Int32Vector.prototype.asGetProperty = function (namespaces, name, flags) {
|
|
if (typeof name === 'number') {
|
|
return this.asGetNumericProperty(name);
|
|
}
|
|
return asGetProperty.call(this, namespaces, name, flags);
|
|
};
|
|
Int32Vector.prototype.asSetProperty = function (namespaces, name, flags, value) {
|
|
if (typeof name === 'number') {
|
|
this.asSetNumericProperty(name, value);
|
|
return;
|
|
}
|
|
return asSetProperty.call(this, namespaces, name, flags, value);
|
|
};
|
|
Uint32Vector.prototype.asGetProperty = function (namespaces, name, flags) {
|
|
if (typeof name === 'number') {
|
|
return this.asGetNumericProperty(name);
|
|
}
|
|
return asGetProperty.call(this, namespaces, name, flags);
|
|
};
|
|
Uint32Vector.prototype.asSetProperty = function (namespaces, name, flags, value) {
|
|
if (typeof name === 'number') {
|
|
this.asSetNumericProperty(name, value);
|
|
return;
|
|
}
|
|
return asSetProperty.call(this, namespaces, name, flags, value);
|
|
};
|
|
Float64Vector.prototype.asGetProperty = function (namespaces, name, flags) {
|
|
if (typeof name === 'number') {
|
|
return this.asGetNumericProperty(name);
|
|
}
|
|
return asGetProperty.call(this, namespaces, name, flags);
|
|
};
|
|
Float64Vector.prototype.asSetProperty = function (namespaces, name, flags, value) {
|
|
if (typeof name === 'number') {
|
|
this.asSetNumericProperty(name, value);
|
|
return;
|
|
}
|
|
return asSetProperty.call(this, namespaces, name, flags, value);
|
|
};
|
|
var GenericVector = function () {
|
|
function vector(length, fixed, type) {
|
|
length = length | 0;
|
|
this._fixed = !(!fixed);
|
|
this._buffer = new Array(length);
|
|
this._type = type;
|
|
this._defaultValue = type ? type.defaultValue : null;
|
|
this._fill(0, length, this._defaultValue);
|
|
}
|
|
vector.applyType = function applyType(type) {
|
|
function parameterizedVector(length, fixed) {
|
|
vector.call(this, length, fixed, type);
|
|
}
|
|
parameterizedVector.prototype = Object.create(vector.prototype);
|
|
parameterizedVector.callable = vector.callable;
|
|
return parameterizedVector;
|
|
};
|
|
vector.callable = function (object) {
|
|
if (object instanceof vector) {
|
|
return object;
|
|
}
|
|
var length = object.asGetProperty(undefined, 'length');
|
|
if (length !== undefined) {
|
|
var v = new vector(length, false);
|
|
for (var i = 0; i < length; i++) {
|
|
v.asSetNumericProperty(i, object.asGetPublicProperty(i));
|
|
}
|
|
return v;
|
|
}
|
|
unexpected();
|
|
};
|
|
vector.prototype._fill = function (index, length, value) {
|
|
for (var i = 0; i < length; i++) {
|
|
this._buffer[index + i] = value;
|
|
}
|
|
};
|
|
vector.prototype.toString = function () {
|
|
var str = '';
|
|
for (var i = 0; i < this._buffer.length; i++) {
|
|
str += this._buffer[i];
|
|
if (i < this._buffer.length - 1) {
|
|
str += ',';
|
|
}
|
|
}
|
|
return str;
|
|
};
|
|
vector.prototype.every = function (callback, thisObject) {
|
|
for (var i = 0; i < this._buffer.length; i++) {
|
|
if (!callback.call(thisObject, this.asGetNumericProperty(i), i, this)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
vector.prototype.filter = function (callback, thisObject) {
|
|
var v = new vector();
|
|
for (var i = 0; i < this._buffer.length; i++) {
|
|
if (callback.call(thisObject, this.asGetNumericProperty(i), i, this)) {
|
|
v.push(this.asGetNumericProperty(i));
|
|
}
|
|
}
|
|
return v;
|
|
};
|
|
vector.prototype.some = function (callback, thisObject) {
|
|
if (arguments.length !== 2) {
|
|
throwError('ArgumentError', Errors.WrongArgumentCountError);
|
|
} else if (!isFunction(callback)) {
|
|
throwError('ArgumentError', Errors.CheckTypeFailedError);
|
|
}
|
|
for (var i = 0; i < this._buffer.length; i++) {
|
|
if (callback.call(thisObject, this.asGetNumericProperty(i), i, this)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
vector.prototype.forEach = function (callback, thisObject) {
|
|
if (!isFunction(callback)) {
|
|
throwError('ArgumentError', Errors.CheckTypeFailedError);
|
|
}
|
|
for (var i = 0; i < this._buffer.length; i++) {
|
|
callback.call(thisObject, this.asGetNumericProperty(i), i, this);
|
|
}
|
|
};
|
|
vector.prototype.map = function (callback, thisObject) {
|
|
if (!isFunction(callback)) {
|
|
throwError('ArgumentError', Errors.CheckTypeFailedError);
|
|
}
|
|
var v = new vector();
|
|
for (var i = 0; i < this._buffer.length; i++) {
|
|
v.push(callback.call(thisObject, this.asGetNumericProperty(i), i, this));
|
|
}
|
|
return v;
|
|
};
|
|
vector.prototype.push = function () {
|
|
this._checkFixed();
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
this._buffer.push(this._coerce(arguments[i]));
|
|
}
|
|
};
|
|
vector.prototype.pop = function () {
|
|
this._checkFixed();
|
|
if (this._buffer.length === 0) {
|
|
return undefined;
|
|
}
|
|
return this._buffer.pop();
|
|
};
|
|
vector.prototype.reverse = function () {
|
|
this._buffer.reverse();
|
|
};
|
|
vector.CASEINSENSITIVE = 1;
|
|
vector.DESCENDING = 2;
|
|
vector.UNIQUESORT = 4;
|
|
vector.RETURNINDEXEDARRAY = 8;
|
|
vector.NUMERIC = 16;
|
|
function defaultCompareFunction(a, b) {
|
|
return String(a).localeCompare(String(b));
|
|
}
|
|
function compare(a, b, options, compareFunction) {
|
|
assertNotImplemented(!(options & CASEINSENSITIVE), 'CASEINSENSITIVE');
|
|
assertNotImplemented(!(options & UNIQUESORT), 'UNIQUESORT');
|
|
assertNotImplemented(!(options & RETURNINDEXEDARRAY), 'RETURNINDEXEDARRAY');
|
|
var result = 0;
|
|
if (!compareFunction) {
|
|
compareFunction = defaultCompareFunction;
|
|
}
|
|
if (options & NUMERIC) {
|
|
a = toNumber(a);
|
|
b = toNumber(b);
|
|
result = a < b ? -1 : a > b ? 1 : 0;
|
|
} else {
|
|
result = compareFunction(a, b);
|
|
}
|
|
if (options & DESCENDING) {
|
|
result *= -1;
|
|
}
|
|
return result;
|
|
}
|
|
vector.prototype.sort = function (comparator) {
|
|
return this._buffer.sort(comparator);
|
|
};
|
|
vector.prototype.asGetNumericProperty = function (i) {
|
|
checkArguments && asCheckVectorGetNumericProperty(i, this._buffer.length);
|
|
return this._buffer[i];
|
|
};
|
|
vector.prototype._coerce = function (v) {
|
|
if (this._type) {
|
|
return this._type.coerce(v);
|
|
} else if (v === undefined) {
|
|
return null;
|
|
}
|
|
return v;
|
|
};
|
|
vector.prototype.asSetNumericProperty = function (i, v) {
|
|
checkArguments && asCheckVectorSetNumericProperty(i, this._buffer.length, this._fixed);
|
|
this._buffer[i] = this._coerce(v);
|
|
};
|
|
vector.prototype.shift = function () {
|
|
this._checkFixed();
|
|
if (this._buffer.length === 0) {
|
|
return undefined;
|
|
}
|
|
return this._buffer.shift();
|
|
};
|
|
vector.prototype._checkFixed = function () {
|
|
if (this._fixed) {
|
|
throwError('RangeError', Errors.VectorFixedError);
|
|
}
|
|
};
|
|
vector.prototype.unshift = function () {
|
|
if (!arguments.length) {
|
|
return;
|
|
}
|
|
this._checkFixed();
|
|
var items = [];
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
items.push(this._coerce(arguments[i]));
|
|
}
|
|
this._buffer.unshift.apply(this._buffer, items);
|
|
};
|
|
Object.defineProperty(vector.prototype, 'length', {
|
|
get: function () {
|
|
return this._buffer.length;
|
|
},
|
|
set: function (length) {
|
|
length = length >>> 0;
|
|
if (length > this._buffer.length) {
|
|
for (var i = this._buffer.length; i < length; i++) {
|
|
this._buffer[i] = this._defaultValue;
|
|
}
|
|
} else {
|
|
this._buffer.length = length;
|
|
}
|
|
true;
|
|
}
|
|
});
|
|
vector.prototype._spliceHelper = function (index, insertCount, deleteCount, args, offset) {
|
|
insertCount = clamp(insertCount, 0, args.length - offset);
|
|
deleteCount = clamp(deleteCount, 0, this._buffer.length - index);
|
|
var items = [];
|
|
for (var i = 0; i < insertCount; i++) {
|
|
items.push(this._coerce(args.asGetNumericProperty(offset + i)));
|
|
}
|
|
this._buffer.splice.apply(this._buffer, [
|
|
index,
|
|
deleteCount
|
|
].concat(items));
|
|
};
|
|
vector.prototype.asGetEnumerableKeys = function () {
|
|
if (vector.prototype === this) {
|
|
return Object.prototype.asGetEnumerableKeys.call(this);
|
|
}
|
|
var keys = [];
|
|
for (var i = 0; i < this._buffer.length; i++) {
|
|
keys.push(i);
|
|
}
|
|
return keys;
|
|
};
|
|
vector.prototype.asHasProperty = function (namespaces, name, flags) {
|
|
if (vector.prototype === this || !isNumeric(name)) {
|
|
return Object.prototype.asHasProperty.call(this, namespaces, name, flags);
|
|
}
|
|
var index = toNumber(name);
|
|
return index >= 0 && index < this._buffer.length;
|
|
};
|
|
return vector;
|
|
}();
|
|
GenericVector.prototype.asGetProperty = function (namespaces, name, flags) {
|
|
if (typeof name === 'number') {
|
|
return this.asGetNumericProperty(name);
|
|
}
|
|
return asGetProperty.call(this, namespaces, name, flags);
|
|
};
|
|
GenericVector.prototype.asSetProperty = function (namespaces, name, flags, value) {
|
|
if (typeof name === 'number') {
|
|
this.asSetNumericProperty(name, value);
|
|
return;
|
|
}
|
|
return asSetProperty.call(this, namespaces, name, flags, value);
|
|
};
|
|
function arraySort(o, args) {
|
|
if (args.length === 0) {
|
|
return o.sort();
|
|
}
|
|
var compareFunction, options = 0;
|
|
if (args[0] instanceof Function) {
|
|
compareFunction = args[0];
|
|
} else if (isNumber(args[0])) {
|
|
options = args[0];
|
|
}
|
|
if (isNumber(args[1])) {
|
|
options = args[1];
|
|
}
|
|
o.sort(function (a, b) {
|
|
return asCompare(a, b, options, compareFunction);
|
|
});
|
|
return o;
|
|
}
|
|
function ArrayClass(domain, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('Array', Array, ApplicationDomain.passthroughCallable(Array));
|
|
c.extendBuiltin(baseClass);
|
|
var CACHE_NUMERIC_COMPARATORS = true;
|
|
var numericComparatorCache = createEmptyObject();
|
|
c.native = {
|
|
static: {
|
|
_pop: function _pop(o) {
|
|
return o.pop();
|
|
},
|
|
_reverse: function _reverse(o) {
|
|
return o.reverse();
|
|
},
|
|
_concat: function _concat(o, args) {
|
|
return o.concat.apply(o, args);
|
|
},
|
|
_shift: function _shift(o) {
|
|
return o.shift();
|
|
},
|
|
_slice: function _slice(o, A, B) {
|
|
return o.slice(A, B);
|
|
},
|
|
_unshift: function _unshift(o, args) {
|
|
return o.unshift.apply(o, args);
|
|
},
|
|
_splice: function _splice(o, args) {
|
|
return o.splice.apply(o, args);
|
|
},
|
|
_sort: function _sort(o, args) {
|
|
if (args.length === 0) {
|
|
return o.sort();
|
|
}
|
|
var compareFunction, options = 0;
|
|
if (args[0] instanceof Function) {
|
|
compareFunction = args[0];
|
|
} else if (isNumber(args[0])) {
|
|
options = args[0];
|
|
}
|
|
if (isNumber(args[1])) {
|
|
options = args[1];
|
|
}
|
|
o.sort(function (a, b) {
|
|
return asCompare(a, b, options, compareFunction);
|
|
});
|
|
return o;
|
|
},
|
|
_sortOn: function _sortOn(o, names, options) {
|
|
if (isString(names)) {
|
|
names = [
|
|
names
|
|
];
|
|
}
|
|
if (isNumber(options)) {
|
|
options = [
|
|
options
|
|
];
|
|
}
|
|
for (var i = names.length - 1; i >= 0; i--) {
|
|
var key = Multiname.getPublicQualifiedName(names[i]);
|
|
if (CACHE_NUMERIC_COMPARATORS && options[i] & SORT_NUMERIC) {
|
|
var str = 'var x = toNumber(a.' + key + '), y = toNumber(b.' + key + ');';
|
|
if (options[i] & SORT_DESCENDING) {
|
|
str += 'return x < y ? 1 : (x > y ? -1 : 0);';
|
|
} else {
|
|
str += 'return x < y ? -1 : (x > y ? 1 : 0);';
|
|
}
|
|
var numericComparator = numericComparatorCache[str];
|
|
if (!numericComparator) {
|
|
numericComparator = numericComparatorCache[str] = new Function('a', 'b', str);
|
|
}
|
|
o.sort(numericComparator);
|
|
} else {
|
|
o.sort(function (a, b) {
|
|
return asCompare(a[key], b[key], options[i] | 0);
|
|
});
|
|
}
|
|
}
|
|
return o;
|
|
},
|
|
_indexOf: function _indexOf(o, searchElement, fromIndex) {
|
|
return o.indexOf(searchElement, fromIndex);
|
|
},
|
|
_lastIndexOf: function _lastIndexOf(o, searchElement, fromIndex) {
|
|
return o.lastIndexOf(searchElement, fromIndex);
|
|
},
|
|
_every: function _every(o, callback, thisObject) {
|
|
for (var i = 0; i < o.length; i++) {
|
|
if (callback.call(thisObject, o[i], i, o) !== true) {
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
_filter: function _filter(o, callback, thisObject) {
|
|
var result = [];
|
|
for (var i = 0; i < o.length; i++) {
|
|
if (callback.call(thisObject, o[i], i, o) === true) {
|
|
result.push(o[i]);
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
_forEach: function _forEach(o, callback, thisObject) {
|
|
return o.forEach(callback, thisObject);
|
|
},
|
|
_map: function _map(o, callback, thisObject) {
|
|
return o.map(callback, thisObject);
|
|
},
|
|
_some: function _some(o, callback, thisObject) {
|
|
return o.some(callback, thisObject);
|
|
}
|
|
},
|
|
instance: {
|
|
pop: Array.prototype.pop,
|
|
push: Array.prototype.push,
|
|
unshift: Array.prototype.unshift,
|
|
length: {
|
|
get: function length() {
|
|
return this.length;
|
|
},
|
|
set: function length(newLength) {
|
|
this.length = newLength;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
c.coerce = function (value) {
|
|
return value;
|
|
};
|
|
c.isInstanceOf = function (value) {
|
|
return true;
|
|
};
|
|
return c;
|
|
}
|
|
var XMLClass, XMLListClass, QNameClass, ASXML, XML, ASXMLList, XMLList;
|
|
var isXMLType, isXMLName, XMLParser;
|
|
(function () {
|
|
function XMLEncoder(ancestorNamespaces, indentLevel, prettyPrinting) {
|
|
function visit(node, encode) {
|
|
if (node.isXML) {
|
|
switch (node.kind) {
|
|
case 'element':
|
|
return encode.element(node);
|
|
case 'attribute':
|
|
return encode.attribute(node);
|
|
case 'text':
|
|
return encode.text(node);
|
|
case 'cdata':
|
|
return encode.cdata(node);
|
|
case 'comment':
|
|
return encode.comment(node);
|
|
case 'processing-instruction':
|
|
return encode.pi(node);
|
|
}
|
|
} else if (node.isXMLList) {
|
|
return encode.list(node);
|
|
} else {
|
|
throw 'Not implemented';
|
|
}
|
|
}
|
|
function encode(node, encoder) {
|
|
return visit(node, {
|
|
element: function (n) {
|
|
var s, a;
|
|
var ns = n.name.mn.namespaces[0];
|
|
var prefix = ns.prefix ? ns.prefix + ':' : '';
|
|
s = '<' + prefix + n.name.localName;
|
|
var namespaceDeclarations = [];
|
|
if (ns.prefix || ns.uri) {
|
|
namespaceDeclarations.push(ns);
|
|
}
|
|
if (prefix) {
|
|
namespaceDeclarations[ns.prefix] = true;
|
|
}
|
|
var t = n;
|
|
while (t) {
|
|
for (var i = 0; i < t.inScopeNamespaces.length; i++) {
|
|
ns = t.inScopeNamespaces[i];
|
|
if (!namespaceDeclarations[ns.prefix]) {
|
|
namespaceDeclarations.push(ns);
|
|
namespaceDeclarations[ns.prefix] = true;
|
|
}
|
|
}
|
|
t = t.parent;
|
|
}
|
|
for (var i = 0; i < namespaceDeclarations.length; i++) {
|
|
a = namespaceDeclarations[i];
|
|
if (a.prefix) {
|
|
s += ' xmlns:' + a.prefix + '="' + a.uri + '"';
|
|
} else {
|
|
s += ' xmlns="' + a.uri + '"';
|
|
}
|
|
}
|
|
for (var i = 0; i < n.attributes.length; i++) {
|
|
a = n.attributes[i];
|
|
var ns = n.name.uri;
|
|
var prefix = n.prefix ? ns.prefix + ':' : '';
|
|
var name = prefix + a.name.localName;
|
|
s += ' ' + name + '="' + a.value + '"';
|
|
}
|
|
if (n.children.length) {
|
|
s += '>';
|
|
for (var i = 0; i < n.children.length; i++) {
|
|
s += visit(n.children[i], this);
|
|
}
|
|
s += '</' + prefix + n.name.mn.name + '>';
|
|
} else {
|
|
s += '/>';
|
|
}
|
|
return s;
|
|
},
|
|
text: function (text) {
|
|
return escapeAttributeValue(text.value);
|
|
},
|
|
attribute: function (n) {
|
|
return escapeAttributeValue(n.value);
|
|
},
|
|
cdata: function (n) {
|
|
},
|
|
comment: function (n) {
|
|
},
|
|
pi: function (n) {
|
|
},
|
|
doctype: function (n) {
|
|
},
|
|
list: function (n) {
|
|
var s = '';
|
|
for (var i = 0; i < n.children.length; i++) {
|
|
if (i > 0) {
|
|
s += '\n';
|
|
}
|
|
s += toXMLString(n.children[i], []);
|
|
}
|
|
return s;
|
|
}
|
|
});
|
|
}
|
|
this.encode = encode;
|
|
}
|
|
function escapeAttributeValue(v) {
|
|
return v.replace('&', '&').replace('<', '<').replace('>', '>');
|
|
}
|
|
XMLParser = function XMLParser() {
|
|
function parseXml(s, sink) {
|
|
var i = 0, scopes = [
|
|
{
|
|
space: 'default',
|
|
xmlns: '',
|
|
namespaces: {
|
|
'xmlns': 'http://www.w3.org/2000/xmlns/',
|
|
'xml': 'http://www.w3.org/XML/1998/namespace'
|
|
}
|
|
}
|
|
];
|
|
function trim(s) {
|
|
return s.replace(/^\s+/, '').replace(/\s+$/, '');
|
|
}
|
|
function resolveEntities(s) {
|
|
return s.replace(/&([^;]+);/g, function (all, entity) {
|
|
if (entity.substring(0, 2) === '#x') {
|
|
return String.fromCharCode(parseInt(entity.substring(2), 16));
|
|
} else if (entity.substring(0, 1) === '#') {
|
|
return String.fromCharCode(parseInt(entity.substring(1), 10));
|
|
}
|
|
switch (entity) {
|
|
case 'lt':
|
|
return '<';
|
|
case 'gt':
|
|
return '>';
|
|
case 'amp':
|
|
return '&';
|
|
}
|
|
throw 'Unknown entity: ' + entity;
|
|
});
|
|
}
|
|
function isWhitespacePreserved() {
|
|
for (var j = scopes.length - 1; j >= 0; --j) {
|
|
if (scopes[j].space === 'preserve') {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function lookupDefaultNs() {
|
|
for (var j = scopes.length - 1; j >= 0; --j) {
|
|
if (scopes[j].hasOwnProperty('xmlns')) {
|
|
return scopes[j].xmlns;
|
|
}
|
|
}
|
|
}
|
|
function lookupNs(prefix) {
|
|
for (var j = scopes.length - 1; j >= 0; --j) {
|
|
if (scopes[j].namespaces.hasOwnProperty(prefix)) {
|
|
return scopes[j].namespaces[prefix];
|
|
}
|
|
}
|
|
throw 'Unknown namespace: ' + prefix;
|
|
}
|
|
function getName(name, resolveDefaultNs) {
|
|
var j = name.indexOf(':');
|
|
if (j >= 0) {
|
|
var namespace = lookupNs(name.substring(0, j));
|
|
var prefix = name.substring(0, j);
|
|
var localName = name.substring(j + 1);
|
|
return {
|
|
name: namespace + '::' + localName,
|
|
localName: localName,
|
|
prefix: prefix,
|
|
namespace: namespace
|
|
};
|
|
} else if (resolveDefaultNs) {
|
|
return {
|
|
name: name,
|
|
localName: name,
|
|
prefix: '',
|
|
namespace: lookupDefaultNs()
|
|
};
|
|
} else {
|
|
return {
|
|
name: name,
|
|
localName: name,
|
|
prefix: '',
|
|
namespace: ''
|
|
};
|
|
}
|
|
}
|
|
var whitespaceMap = {
|
|
'10': true,
|
|
'13': true,
|
|
'9': true,
|
|
'32': true
|
|
};
|
|
function isWhitespace(s, index) {
|
|
return s.charCodeAt(index) in whitespaceMap;
|
|
}
|
|
function parseContent(s, start) {
|
|
var pos = start, name, attributes = [];
|
|
function skipWs() {
|
|
while (pos < s.length && isWhitespace(s, pos)) {
|
|
++pos;
|
|
}
|
|
}
|
|
while (pos < s.length && !isWhitespace(s, pos) && s.charAt(pos) !== '>' && s.charAt(pos) !== '/') {
|
|
++pos;
|
|
}
|
|
name = s.substring(start, pos);
|
|
skipWs();
|
|
while (pos < s.length && s.charAt(pos) !== '>' && s.charAt(pos) !== '/' && s.charAt(pos) !== '?') {
|
|
skipWs();
|
|
var attrName = '', attrValue = '';
|
|
while (pos < s.length && !isWhitespace(s, pos) && s.charAt(pos) !== '=') {
|
|
attrName += s.charAt(pos);
|
|
++pos;
|
|
}
|
|
skipWs();
|
|
if (s.charAt(pos) !== '=')
|
|
throw '\'=\' expected';
|
|
++pos;
|
|
skipWs();
|
|
var attrEndChar = s.charAt(pos);
|
|
if (attrEndChar !== '"' && attrEndChar !== '\'')
|
|
throw 'Quote expected';
|
|
var attrEndIndex = s.indexOf(attrEndChar, ++pos);
|
|
if (attrEndIndex < 0)
|
|
throw new 'Unexpected EOF[6]'();
|
|
attrValue = s.substring(pos, attrEndIndex);
|
|
attributes.push({
|
|
name: attrName,
|
|
value: resolveEntities(attrValue)
|
|
});
|
|
pos = attrEndIndex + 1;
|
|
skipWs();
|
|
}
|
|
return {
|
|
name: name,
|
|
attributes: attributes,
|
|
parsed: pos - start
|
|
};
|
|
}
|
|
while (i < s.length) {
|
|
var ch = s.charAt(i);
|
|
var j = i;
|
|
if (ch === '<') {
|
|
++j;
|
|
var ch2 = s.charAt(j), q, name;
|
|
switch (ch2) {
|
|
case '/':
|
|
++j;
|
|
q = s.indexOf('>', j);
|
|
if (q < 0) {
|
|
throw 'Unexpected EOF[1]';
|
|
}
|
|
name = getName(s.substring(j, q), true);
|
|
sink.endElement(name);
|
|
scopes.pop();
|
|
j = q + 1;
|
|
break;
|
|
case '?':
|
|
++j;
|
|
var content = parseContent(s, j);
|
|
if (s.substring(j + content.parsed, j + content.parsed + 2) != '?>') {
|
|
throw 'Unexpected EOF[2]';
|
|
}
|
|
sink.pi(content.name, content.attributes);
|
|
j += content.parsed + 2;
|
|
break;
|
|
case '!':
|
|
if (s.substring(j + 1, j + 3) === '--') {
|
|
q = s.indexOf('-->', j + 3);
|
|
if (q < 0) {
|
|
throw 'Unexpected EOF[3]';
|
|
}
|
|
sink.comment(s.substring(j + 3, q));
|
|
j = q + 3;
|
|
} else if (s.substring(j + 1, j + 8) === '[CDATA[') {
|
|
q = s.indexOf(']]>', j + 8);
|
|
if (q < 0) {
|
|
throw 'Unexpected EOF[4]';
|
|
}
|
|
sink.cdata(s.substring(j + 8, q));
|
|
j = q + 3;
|
|
} else if (s.substring(j + 1, j + 8) === 'DOCTYPE') {
|
|
var q2 = s.indexOf('[', j + 8), complexDoctype = false;
|
|
q = s.indexOf('>', j + 8);
|
|
if (q < 0) {
|
|
throw 'Unexpected EOF[5]';
|
|
}
|
|
if (q2 > 0 && q > q2) {
|
|
q = s.indexOf(']>', j + 8);
|
|
if (q < 0) {
|
|
throw 'Unexpected EOF[7]';
|
|
}
|
|
complexDoctype = true;
|
|
}
|
|
var doctypeContent = s.substring(j + 8, q + (complexDoctype ? 1 : 0));
|
|
sink.doctype(doctypeContent);
|
|
j = q + (complexDoctype ? 2 : 1);
|
|
} else {
|
|
throw 'Unknown !tag';
|
|
}
|
|
break;
|
|
default:
|
|
var content = parseContent(s, j);
|
|
var isClosed = false;
|
|
if (s.substring(j + content.parsed, j + content.parsed + 2) === '/>') {
|
|
isClosed = true;
|
|
} else if (s.substring(j + content.parsed, j + content.parsed + 1) !== '>') {
|
|
throw 'Unexpected EOF[2]';
|
|
}
|
|
var scope = {
|
|
namespaces: []
|
|
};
|
|
var contentAttributes = content.attributes;
|
|
for (q = 0; q < contentAttributes.length; ++q) {
|
|
var attribute = contentAttributes[q];
|
|
var attributeName = attribute.name;
|
|
if (attributeName.substring(0, 6) === 'xmlns:') {
|
|
var prefix = attributeName.substring(6);
|
|
var uri = attribute.value;
|
|
scope.namespaces[prefix] = trim(uri);
|
|
scope.namespaces.push({
|
|
uri: uri,
|
|
prefix: prefix
|
|
});
|
|
delete contentAttributes[q];
|
|
} else if (attributeName === 'xmlns') {
|
|
var uri = attribute.value;
|
|
scope.namespaces['xmlns'] = trim(uri);
|
|
scope.namespaces.push({
|
|
uri: uri,
|
|
prefix: ''
|
|
});
|
|
delete contentAttributes[q];
|
|
} else if (attributeName.substring(0, 4) === 'xml:') {
|
|
scope[attributeName.substring(4)] = trim(attribute.value);
|
|
} else if (attributeName.substring(0, 3) === 'xml') {
|
|
throw 'Invalid xml attribute';
|
|
} else {
|
|
}
|
|
}
|
|
scopes.push(scope);
|
|
var attributes = [];
|
|
for (q = 0; q < contentAttributes.length; ++q) {
|
|
attribute = contentAttributes[q];
|
|
if (attribute) {
|
|
attributes.push({
|
|
name: getName(attribute.name, false),
|
|
value: attribute.value
|
|
});
|
|
}
|
|
}
|
|
sink.beginElement(getName(content.name, true), attributes, scope, isClosed);
|
|
j += content.parsed + (isClosed ? 2 : 1);
|
|
if (isClosed)
|
|
scopes.pop();
|
|
break;
|
|
}
|
|
} else {
|
|
do {
|
|
if (++j >= s.length)
|
|
break;
|
|
} while (s.charAt(j) !== '<');
|
|
var text = s.substring(i, j);
|
|
var isWs = text.replace(/^\s+/, '').length === 0;
|
|
if (!isWs || isWhitespacePreserved()) {
|
|
sink.text(resolveEntities(text), isWs);
|
|
}
|
|
}
|
|
i = j;
|
|
}
|
|
}
|
|
this.parseFromString = function (s, mimeType) {
|
|
var currentElement = new XML('element', '', '', '');
|
|
var elementsStack = [];
|
|
parseXml(s, {
|
|
beginElement: function (name, attrs, scope, isEmpty) {
|
|
var parent = currentElement;
|
|
elementsStack.push(parent);
|
|
currentElement = createNode('element', name.namespace, name.localName, name.prefix);
|
|
for (var i = 0; i < attrs.length; ++i) {
|
|
var rawAttr = attrs[i];
|
|
var attr = createNode('attribute', rawAttr.name.namespace, rawAttr.name.localName, rawAttr.name.prefix);
|
|
attr.value = rawAttr.value;
|
|
currentElement.attributes.push(attr);
|
|
}
|
|
var namespaces = scope.namespaces;
|
|
for (var i = 0; i < namespaces.length; ++i) {
|
|
var rawNs = namespaces[i];
|
|
var ns = ASNamespace.createNamespace(rawNs.uri, rawNs.prefix);
|
|
currentElement.inScopeNamespaces.push(ns);
|
|
}
|
|
parent.insert(parent.length(), currentElement);
|
|
if (isEmpty) {
|
|
currentElement = elementsStack.pop();
|
|
}
|
|
},
|
|
endElement: function (name) {
|
|
currentElement = elementsStack.pop();
|
|
},
|
|
text: function (text, isWhitespace) {
|
|
var node = createNode('text', '', '');
|
|
node.value = text;
|
|
currentElement.insert(currentElement.length(), node);
|
|
},
|
|
cdata: function (text) {
|
|
var node = createNode('text', '', '');
|
|
node.value = text;
|
|
currentElement.insert(currentElement.length(), node);
|
|
},
|
|
comment: function (text) {
|
|
},
|
|
pi: function (name, attrs) {
|
|
},
|
|
doctype: function (text) {
|
|
}
|
|
});
|
|
return currentElement;
|
|
};
|
|
function createNode(kind, uri, name, prefix) {
|
|
return new XML(kind, uri, name, prefix);
|
|
}
|
|
};
|
|
var xmlParser = new XMLParser();
|
|
isXMLType = function isXMLType(val) {
|
|
return val.isXML || val.isXMLList;
|
|
};
|
|
function toString(node) {
|
|
if (typeof node === 'object' && node !== null) {
|
|
switch (node.kind) {
|
|
case 'text':
|
|
case 'attribute':
|
|
return node.value;
|
|
default:
|
|
if (node.hasSimpleContent()) {
|
|
var str = '';
|
|
node.children.forEach(function (v, i) {
|
|
str += toString(v);
|
|
});
|
|
return str;
|
|
}
|
|
return toXMLString(node);
|
|
}
|
|
} else {
|
|
return String(node);
|
|
}
|
|
}
|
|
function toXMLString(node, ancestorNamespaces, indentLevel) {
|
|
return new XMLEncoder(ancestorNamespaces, indentLevel, true).encode(node);
|
|
}
|
|
function toXML(v) {
|
|
if (v === null) {
|
|
throw new TypeError(formatErrorMessage(Errors.ConvertNullToObjectError));
|
|
} else if (v === undefined) {
|
|
throw new TypeError(formatErrorMessage(Errors.ConvertUndefinedToObjectError));
|
|
} else if (v.isXML) {
|
|
return v;
|
|
} else if (v.isXMLList) {
|
|
if (v.length() === 1) {
|
|
return v.children[0];
|
|
}
|
|
throw new TypeError(formatErrorMessage(Errors.XMLMarkupMustBeWellFormed));
|
|
} else {
|
|
var x = xmlParser.parseFromString(String(v));
|
|
if (x.length() === 0) {
|
|
var x = new XML('text');
|
|
return x;
|
|
} else if (x.length() === 1) {
|
|
x.children[0].parent = null;
|
|
return x.children[0];
|
|
}
|
|
throw 'SyntaxError in ToXML';
|
|
}
|
|
}
|
|
var defaultNamespace = '';
|
|
function toXMLList(value) {
|
|
if (value === null) {
|
|
throw new TypeError(formatErrorMessage(Errors.ConvertNullToObjectError));
|
|
} else if (value === undefined) {
|
|
throw new TypeError(formatErrorMessage(Errors.ConvertUndefinedToObjectError));
|
|
} else if (value instanceof XML) {
|
|
var xl = new XMLList(value.parent, value.name);
|
|
xl.append(value);
|
|
return xl;
|
|
} else if (value instanceof XMLList) {
|
|
return value;
|
|
} else {
|
|
var s = '<parent xmlns=\'' + defaultNamespace + '\'>' + String(value) + '</parent>';
|
|
var x = new ASXML(s);
|
|
var xl = new XMLList();
|
|
for (var i = 0; i < x.length(); i++) {
|
|
var v = x.children[i];
|
|
v.parent = null;
|
|
xl.append(v);
|
|
}
|
|
return xl;
|
|
}
|
|
}
|
|
function toAttributeName(v) {
|
|
if (v === undefined || v === null || typeof v === 'boolean' || typeof v === 'number') {
|
|
throw 'TypeError: invalid operand to ToAttributeName()';
|
|
} else if (isXMLType(v)) {
|
|
v = toString(v);
|
|
} else if (v instanceof Object && v !== null) {
|
|
if (v instanceof QName) {
|
|
return new QName(v.uri, v.localName, true);
|
|
}
|
|
v = toString(v);
|
|
}
|
|
if (typeof v === 'string') {
|
|
var ns = new ASNamespace();
|
|
var qn = new QName(ns, v, true);
|
|
} else {
|
|
}
|
|
return qn;
|
|
}
|
|
function toXMLName(mn) {
|
|
return new QName(mn);
|
|
}
|
|
function getDefaultNamespace(scope) {
|
|
while (scope) {
|
|
var obj = scope.object;
|
|
if (obj.defaultNamepsace !== undefined) {
|
|
return obj.defaultNamespace;
|
|
}
|
|
scope = scope.parent;
|
|
}
|
|
var ns = ASNamespace.createNamespace('', '');
|
|
return ns;
|
|
}
|
|
isXMLName = function isXMLName(v) {
|
|
try {
|
|
var qn = new QName(v);
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
function asGetProperty(namespaces, name, flags, isMethod) {
|
|
var mn = isNumeric(name) ? toNumber(name) : name instanceof QName ? name.mn : new Multiname(namespaces ? namespaces : [
|
|
ASNamespace.PUBLIC
|
|
], name, flags);
|
|
return this.getProperty(mn, isMethod);
|
|
}
|
|
function asSetProperty(namespaces, name, flags, value) {
|
|
var mn = isNumeric(name) ? toNumber(name) : name instanceof QName ? name.mn : new Multiname(namespaces ? namespaces : [
|
|
ASNamespace.PUBLIC
|
|
], name, flags);
|
|
this.setProperty(mn, value);
|
|
}
|
|
function asHasProperty(namespaces, name, flags) {
|
|
var mn = isNumeric(name) ? toNumber(name) : name instanceof QName ? name.mn : new Multiname(namespaces ? namespaces : [
|
|
ASNamespace.PUBLIC
|
|
], name, flags);
|
|
return this.hasProperty(mn);
|
|
}
|
|
function asCallProperty(namespaces, name, flags, isLex, args) {
|
|
var receiver = isLex ? null : this;
|
|
var property = this.asGetProperty(namespaces, name, flags, true);
|
|
if (!property) {
|
|
return this.toString().asCallProperty(namespaces ? namespaces : [
|
|
ASNamespace.PUBLIC
|
|
], name, flags, isLex, args);
|
|
}
|
|
return property.apply(receiver, args);
|
|
}
|
|
var ATTR_NAME = 1;
|
|
var ELEM_NAME = 2;
|
|
var ANY_NAME = 4;
|
|
var ANY_NAMESPACE = 8;
|
|
function nameKind(mn) {
|
|
var flags = 0;
|
|
if (mn.isAttribute()) {
|
|
flags |= ATTR_NAME;
|
|
} else {
|
|
flags |= ELEM_NAME;
|
|
}
|
|
if (mn.isAnyName()) {
|
|
flags |= ANY_NAME;
|
|
}
|
|
if (mn.isAnyNamespace()) {
|
|
flags |= ANY_NAMESPACE;
|
|
}
|
|
return flags;
|
|
}
|
|
XMLClass = function XMLClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var FLAG_IGNORE_COMMENTS = 1;
|
|
var FLAG_IGNORE_PROCESSING_INSTRUCTIONS = 2;
|
|
var FLAG_IGNORE_WHITESPACE = 4;
|
|
var FLAG_PRETTY_PRINTING = 8;
|
|
ASXML = function (value) {
|
|
if (!(this instanceof ASXML)) {
|
|
if (value instanceof ASXML) {
|
|
return value;
|
|
}
|
|
return new ASXML(value);
|
|
}
|
|
if (value === null || value === undefined) {
|
|
value = '';
|
|
}
|
|
var x = toXML(value);
|
|
if (isXMLType(value)) {
|
|
x = x.deepCopy();
|
|
}
|
|
return x;
|
|
};
|
|
XML = function (kind, uri, name, prefix) {
|
|
if (kind === undefined) {
|
|
kind = 'text';
|
|
}
|
|
if (uri === undefined) {
|
|
uri = '';
|
|
}
|
|
if (name === undefined) {
|
|
name = '';
|
|
}
|
|
this.init(kind, uri, name, prefix);
|
|
};
|
|
var c = new Class('XML', ASXML, ApplicationDomain.passthroughCallable(ASXML));
|
|
c.flags = FLAG_IGNORE_COMMENTS | FLAG_IGNORE_PROCESSING_INSTRUCTIONS | FLAG_IGNORE_WHITESPACE | FLAG_PRETTY_PRINTING;
|
|
c.prettyIndent = 2;
|
|
c.extend(baseClass);
|
|
var Xp = XML.prototype = ASXML.prototype;
|
|
Xp.init = function init(kind, uri, name, prefix) {
|
|
this.name = new QName(new Multiname([
|
|
new ASNamespace(prefix, uri)
|
|
], name));
|
|
this.kind = kind;
|
|
this.parent = null;
|
|
this.inScopeNamespaces = [];
|
|
switch (kind) {
|
|
case 'element':
|
|
this.attributes = [];
|
|
this.children = [];
|
|
break;
|
|
case 'attribute':
|
|
case 'text':
|
|
this.value = '';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return this;
|
|
};
|
|
Xp.length = function () {
|
|
if (!this.children) {
|
|
return 0;
|
|
}
|
|
return this.children.length;
|
|
};
|
|
Xp.canHandleProperties = true;
|
|
Xp.deepCopy = function () {
|
|
return new ASXML(toXMLString(this));
|
|
};
|
|
Xp.resolveValue = function resolveValue() {
|
|
return this;
|
|
};
|
|
Xp.hasSimpleContent = function hasSimpleContent() {
|
|
if (this.kind === 'comment' || this.kind === 'processing-instruction') {
|
|
return false;
|
|
}
|
|
var result = true;
|
|
if (this.children) {
|
|
this.children.forEach(function (v) {
|
|
if (v.kind === 'element') {
|
|
result = false;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
};
|
|
Xp.asGetEnumerableKeys = function asGetEnumerableKeys() {
|
|
if (Xp === this) {
|
|
return Object.prototype.asGetEnumerableKeys.call(this);
|
|
}
|
|
var keys = [];
|
|
this.children.forEach(function (v, i) {
|
|
keys.push(v.name);
|
|
});
|
|
return keys;
|
|
};
|
|
function setAttribute(node, name, value) {
|
|
if (node.nodeType === Node.DOCUMENT_NODE) {
|
|
node.childNodes[0].setAttribute(name, value);
|
|
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
node.setAttribute(name, value);
|
|
} else {
|
|
throw 'error or unhandled case in setAttribute';
|
|
}
|
|
}
|
|
Xp.setProperty = function (p, v) {
|
|
var x, i, c, n;
|
|
x = this;
|
|
if (p === p >>> 0) {
|
|
throw 'TypeError in XML.prototype.setProperty(): invalid property name ' + p;
|
|
}
|
|
if (x.kind === 'text' || x.kind === 'comment' || x.kind === 'processing-instruction' || x.kind === 'attribute') {
|
|
return;
|
|
}
|
|
if (!v || !v.isXML && !v.isXMLList || v.kind === 'text' || v.kind === 'attribute') {
|
|
c = toString(v);
|
|
} else {
|
|
c = v.deepCopy();
|
|
}
|
|
n = toXMLName(p);
|
|
if (n.isAttr) {
|
|
if (!this.attributes) {
|
|
return;
|
|
}
|
|
this.attributes.forEach(function (v, i, o) {
|
|
if (v.name === n.localName) {
|
|
delete o[i];
|
|
}
|
|
});
|
|
var a = new XML('attribute', n.uri, n.localName);
|
|
a.value = v;
|
|
a.parent = this;
|
|
this.attributes.push(a);
|
|
return;
|
|
}
|
|
var isValidName = isXMLName(n);
|
|
if (!isValidName && n.localName !== '*') {
|
|
return;
|
|
}
|
|
var i = undefined;
|
|
var primitiveAssign = !isXMLType(c) && n.localName !== '*';
|
|
for (var k = x.length() - 1; k >= 0; k--) {
|
|
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)) {
|
|
if (i !== undefined) {
|
|
x.deleteByIndex(String(i));
|
|
}
|
|
i = k;
|
|
}
|
|
}
|
|
if (i === undefined) {
|
|
i = x.length();
|
|
if (primitiveAssign) {
|
|
if (n.uri === null) {
|
|
var name = new QName(getDefaultNamespace(scope), n);
|
|
} else {
|
|
var name = new QName(n);
|
|
}
|
|
var y = new XML('element', name.uri, name.localName, name.prefix);
|
|
y.parent = x;
|
|
var ns = name.getNamespace();
|
|
x.replace(String(i), y);
|
|
y.addInScopeNamespace(ns);
|
|
}
|
|
}
|
|
if (primitiveAssign) {
|
|
x.children[i].children = [];
|
|
var s = toString(c);
|
|
if (s !== '') {
|
|
x.children[i].replace('0', s);
|
|
}
|
|
} else {
|
|
x.replace(String(i), c);
|
|
}
|
|
return;
|
|
};
|
|
Xp.asGetProperty = asGetProperty;
|
|
Xp.asGetResolvedStringProperty = asGetResolvedStringPropertyFallback;
|
|
Xp.asSetProperty = asSetProperty;
|
|
Xp.asHasProperty = asHasProperty;
|
|
Xp.asCallProperty = asCallProperty;
|
|
Xp.getProperty = function (mn, isMethod) {
|
|
if (isMethod) {
|
|
var resolved = Multiname.isQName(mn) ? mn : this.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags);
|
|
return this[Multiname.getQualifiedName(resolved)];
|
|
}
|
|
if (!Multiname.isQName(mn) && isNumeric(mn)) {
|
|
if (Number(0) === 0) {
|
|
return this;
|
|
}
|
|
return null;
|
|
}
|
|
var x = this;
|
|
var name = toXMLName(mn);
|
|
var xl = new XMLList(x, name);
|
|
var flags = nameKind(name.mn);
|
|
var anyName = flags & ANY_NAME;
|
|
var anyNamespace = flags & ANY_NAMESPACE;
|
|
if (flags & ATTR_NAME) {
|
|
if (x.attributes) {
|
|
x.attributes.forEach(function (v, i) {
|
|
if ((anyName || v.name.localName === name.localName) && (anyNamespace || v.name.uri === name.uri)) {
|
|
xl.append(v);
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
x.children.forEach(function (v, i) {
|
|
if ((anyName || v.kind === 'element' && v.name.localName === name.localName) && (anyNamespace || v.kind === 'element' && v.name.uri === name.uri)) {
|
|
xl.append(v);
|
|
}
|
|
});
|
|
}
|
|
return xl;
|
|
};
|
|
Xp.hasProperty = function (mn, isMethod) {
|
|
if (isMethod) {
|
|
var resolved = Multiname.isQName(mn) ? mn : this.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags);
|
|
return !(!this[Multiname.getQualifiedName(resolved)]);
|
|
}
|
|
if (!Multiname.isQName(mn) && isNumeric(mn)) {
|
|
if (Number(0) === 0) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
var name = toXMLName(mn);
|
|
var flags = nameKind(name.mn);
|
|
var anyName = flags & ANY_NAME;
|
|
var anyNamespace = flags & ANY_NAMESPACE;
|
|
if (flags & ATTR_NAME) {
|
|
return this.attributes.some(function (v, i) {
|
|
if ((anyName || v.name.localName === name.localName) && (anyNamespace || v.name.uri === name.uri)) {
|
|
return true;
|
|
}
|
|
});
|
|
if (x.attributes) {
|
|
x.attributes.forEach(function (v, i) {
|
|
if ((anyName || v.name.localName === name.localName) && (anyNamespace || v.name.uri === name.uri)) {
|
|
xl.append(v);
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
if (this.children.some(function (v, i) {
|
|
if ((anyName || v.kind === 'element' && v.name.localName === name.localName) && (anyNamespace || v.kind === 'element' && v.name.uri === name.uri)) {
|
|
return true;
|
|
}
|
|
})) {
|
|
return true;
|
|
}
|
|
var resolved = Multiname.isQName(mn) ? mn : this.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags);
|
|
return !(!this[Multiname.getQualifiedName(resolved)]);
|
|
}
|
|
};
|
|
Xp.delete = function (key, isMethod) {
|
|
notImplemented('XML.[[Delete]]');
|
|
};
|
|
Xp.deleteByIndex = function (p) {
|
|
var x = this;
|
|
var i = p >>> 0;
|
|
if (String(i) !== String(p)) {
|
|
throw 'TypeError in XML.prototype.deleteByIndex(): invalid index ' + p;
|
|
}
|
|
if (p < x.length()) {
|
|
if (x.children[p]) {
|
|
x.children[p].parent = null;
|
|
delete x.children[p];
|
|
for (q = i + 1; q < x.length(); q++) {
|
|
x.children[q - 1] = x.children[q];
|
|
}
|
|
x.children.length = x.children.length - 1;
|
|
}
|
|
}
|
|
};
|
|
Xp.isXML = true;
|
|
Xp.insert = function insert(p, v) {
|
|
var x, s, i, n;
|
|
x = this;
|
|
if (x.kind === 'text' || x.kind === 'comment' || x.kind === 'processing-instruction' || x.kind === 'attribute') {
|
|
return;
|
|
}
|
|
i = p >>> 0;
|
|
if (String(p) !== String(i)) {
|
|
throw 'TypeError in XML.prototype.insert(): invalid property name ' + p;
|
|
}
|
|
if (x.kind === 'element') {
|
|
var a = x;
|
|
while (a) {
|
|
if (a === v) {
|
|
throw 'Error in XML.prototype.insert()';
|
|
}
|
|
a = a.parent;
|
|
}
|
|
}
|
|
if (x.isXMLList) {
|
|
n = x.length();
|
|
if (n === 0) {
|
|
return;
|
|
}
|
|
} else {
|
|
n = 1;
|
|
}
|
|
for (var j = x.length() - 1; j >= i; j--) {
|
|
x[j + n] = x[j];
|
|
}
|
|
if (x.isXMLList) {
|
|
n = v.length();
|
|
for (var j = 0; j < n; j++) {
|
|
v.children[j].parent = x;
|
|
x[i + j] = v[j];
|
|
}
|
|
} else {
|
|
v.parent = x;
|
|
x.children[i] = v;
|
|
}
|
|
};
|
|
Xp.replace = function (p, v) {
|
|
var x, s;
|
|
x = this;
|
|
if (x.kind === 'text' || x.kind === 'comment' || x.kind === 'processing-instruction' || x.kind === 'attribute') {
|
|
return;
|
|
}
|
|
var i = p >>> 0;
|
|
if (String(p) !== String(i)) {
|
|
throw 'TypeError in XML.prototype.replace(): invalid name ' + p;
|
|
}
|
|
if (i >= x.length()) {
|
|
p = String(x.length());
|
|
}
|
|
if (v.kind === 'element') {
|
|
var a = x;
|
|
while (a) {
|
|
if (a === v) {
|
|
throw 'Error in XML.prototype.replace()';
|
|
}
|
|
a = a.parent;
|
|
}
|
|
}
|
|
if (v.kind === 'element' || v.kind === 'text' || v.kind === 'comment' || v.kind === 'processing-instruction') {
|
|
v.parent = x;
|
|
if (x[p]) {
|
|
x.children[p].parent = null;
|
|
}
|
|
x.children[p] = v;
|
|
} else if (x.isXMLList) {
|
|
x.deleteByIndex(p);
|
|
x.insert(p, v);
|
|
} else {
|
|
s = toString(v);
|
|
t = new XML();
|
|
t.parent = x;
|
|
t.value = s;
|
|
if (x[p]) {
|
|
x.children[p].parent = null;
|
|
}
|
|
x.children[p] = t;
|
|
}
|
|
};
|
|
Xp.addInScopeNamespace = function (ns) {
|
|
var x, s;
|
|
x = this;
|
|
if (x.kind === 'text' || x.kind === 'comment' || x.kind === 'processing-instruction' || x.kind === 'attribute') {
|
|
return;
|
|
}
|
|
if (ns.prefix !== undefined) {
|
|
if (ns.prefix === '' && x.name.uri === '') {
|
|
return;
|
|
}
|
|
var match = null;
|
|
x.inScopeNamespaces.forEach(function (v, i) {
|
|
if (v.prefix === ns.prefix) {
|
|
match = v;
|
|
}
|
|
});
|
|
if (match !== null && match.uri !== ns.uri) {
|
|
x.inScopeNamespaces.forEach(function (v, i) {
|
|
if (v.prefix === match.prefix) {
|
|
x.inScopeNamespaces[i] = ns;
|
|
}
|
|
});
|
|
}
|
|
if (x.name.prefix === ns.prefix) {
|
|
x.name.prefix = undefined;
|
|
}
|
|
x.attributes.forEach(function (v, i) {
|
|
if (v.name.prefix === ns.name.prefix) {
|
|
v.name.prefix = undefined;
|
|
}
|
|
});
|
|
}
|
|
};
|
|
Xp.descendants = function (name) {
|
|
name = toXMLName(name);
|
|
var x = this;
|
|
var xl = new XMLList();
|
|
if (x.kind !== 'element') {
|
|
return xl;
|
|
}
|
|
if (name.isAttr) {
|
|
this.attributes.forEach(function (v, i) {
|
|
if (name.isAny || name.localName === v.name.localName) {
|
|
xl.append(v);
|
|
}
|
|
});
|
|
} else {
|
|
this.children.forEach(function (v, i) {
|
|
if (name.isAny || name.localName === v.name.localName) {
|
|
xl.append(v);
|
|
}
|
|
});
|
|
}
|
|
this.children.forEach(function (v, i) {
|
|
xl.append(v.descendants(name));
|
|
});
|
|
return xl;
|
|
};
|
|
Xp.comments = function () {
|
|
var x = this;
|
|
var xl = new XMLList(x, null);
|
|
x.children.forEach(function (v, i) {
|
|
if (v.kind === 'comment') {
|
|
xl.append(v);
|
|
}
|
|
});
|
|
return xl;
|
|
};
|
|
Xp.text = function () {
|
|
var x = this;
|
|
var xl = new XMLList(x, null);
|
|
x.children.forEach(function (v, i) {
|
|
if (v.kind === 'text') {
|
|
xl.append(v);
|
|
}
|
|
});
|
|
return xl;
|
|
};
|
|
c.native = {
|
|
static: {
|
|
ignoreComments: {
|
|
get: function ignoreComments() {
|
|
return getBitFlags(c.flags, FLAG_IGNORE_COMMENTS);
|
|
},
|
|
set: function ignoreComments(newIgnore) {
|
|
c.flags = setBitFlags(c.flags, FLAG_IGNORE_COMMENTS, newIgnore);
|
|
}
|
|
},
|
|
ignoreProcessingInstructions: {
|
|
get: function ignoreProcessingInstructions() {
|
|
return getBitFlags(c.flags, FLAG_IGNORE_PROCESSING_INSTRUCTIONS);
|
|
},
|
|
set: function ignoreProcessingInstructions(newIgnore) {
|
|
c.flags = setBitFlags(c.flags, FLAG_IGNORE_PROCESSING_INSTRUCTIONS, newIgnore);
|
|
}
|
|
},
|
|
ignoreWhitespace: {
|
|
get: function ignoreWhitespace() {
|
|
return getBitFlags(c.flags, FLAG_IGNORE_WHITESPACE);
|
|
},
|
|
set: function ignoreWhitespace(newIgnore) {
|
|
c.flags = setBitFlags(c.flags, FLAG_IGNORE_WHITESPACE, newIgnore);
|
|
}
|
|
},
|
|
prettyPrinting: {
|
|
get: function prettyPrinting() {
|
|
return getBitFlags(c.flags, FLAG_PRETTY_PRINTING);
|
|
},
|
|
set: function prettyPrinting(newPretty) {
|
|
c.flags = setBitFlags(c.flags, FLAG_PRETTY_PRINTING, newPretty);
|
|
}
|
|
},
|
|
prettyIndent: {
|
|
get: function prettyIndent() {
|
|
return c.prettyIndent;
|
|
},
|
|
set: function prettyIndent(newIndent) {
|
|
c.prettyIndent = newIndent;
|
|
}
|
|
}
|
|
},
|
|
instance: {
|
|
toString: function () {
|
|
return toString(this);
|
|
},
|
|
hasOwnProperty: function hasOwnProperty(P) {
|
|
somewhatImplemented('XML.hasOwnProperty');
|
|
return this.hasProperty(P);
|
|
},
|
|
propertyIsEnumerable: function propertyIsEnumerable(P) {
|
|
notImplemented('XML.propertyIsEnumerable');
|
|
},
|
|
addNamespace: function addNamespace(ns) {
|
|
notImplemented('XML.addNamespace');
|
|
},
|
|
appendChild: function appendChild(child) {
|
|
var children = this.getProperty('*');
|
|
children.setProperty(children.length(), child);
|
|
return this;
|
|
},
|
|
attribute: function attribute(name) {
|
|
return this.getProperty(toAttributeName(name));
|
|
},
|
|
attributes: function attributes() {
|
|
return this.getProperty(toAttributeName('*'));
|
|
},
|
|
child: function child(name) {
|
|
return this.getProperty(name);
|
|
},
|
|
childIndex: function childIndex() {
|
|
notImplemented('XML.childIndex');
|
|
},
|
|
children: function children() {
|
|
var list = new XMLList();
|
|
Array.prototype.push.apply(list.children, this.children);
|
|
return list;
|
|
},
|
|
comments: function comments() {
|
|
return this.comments();
|
|
},
|
|
contains: function contains(value) {
|
|
notImplemented('XML.contains');
|
|
},
|
|
copy: function copy() {
|
|
return this.deepCopy();
|
|
},
|
|
descendants: function descendants(name) {
|
|
if (name === undefined) {
|
|
name = '*';
|
|
}
|
|
return this.descendants(name);
|
|
},
|
|
elements: function elements(name) {
|
|
var x = this;
|
|
var any = false;
|
|
if (name === undefined) {
|
|
name = '*';
|
|
any = true;
|
|
}
|
|
var name = toXMLName(name);
|
|
var xl = new XMLList(this.parent, name);
|
|
x.children.forEach(function (v, i) {
|
|
if (v.kind === 'element' && (any || v.name.localName === name.localName) && (name.uri === null || v.kind === 'element' && v.name.uri === name.uri)) {
|
|
xl.append(v);
|
|
}
|
|
});
|
|
return xl;
|
|
},
|
|
hasComplexContent: function hasComplexContent() {
|
|
notImplemented('XML.hasComplexContent');
|
|
},
|
|
hasSimpleContent: function hasSimpleContent() {
|
|
return this.hasSimpleContent();
|
|
},
|
|
inScopeNamespaces: function inScopeNamespaces() {
|
|
notImplemented('XML.inScopeNamespaces');
|
|
},
|
|
insertChildAfter: function insertChildAfter(child1, child2) {
|
|
notImplemented('XML.insertChildAfter');
|
|
},
|
|
insertChildBefore: function insertChildBefore(child1, child2) {
|
|
notImplemented('XML.insertChildBefore');
|
|
},
|
|
localName: function localName() {
|
|
return this.name.localName;
|
|
},
|
|
name: function name() {
|
|
return this.name;
|
|
},
|
|
_namespace: function _namespace(prefix, argc) {
|
|
somewhatImplemented('XML._namespace()');
|
|
return this.name.uri;
|
|
},
|
|
namespaceDeclarations: function namespaceDeclarations() {
|
|
return new XMLList();
|
|
},
|
|
nodeKind: function nodeKind() {
|
|
return this.kind;
|
|
},
|
|
normalize: function normalize() {
|
|
notImplemented('XML.normalize');
|
|
},
|
|
parent: function parent() {
|
|
notImplemented('XML.parent');
|
|
},
|
|
processingInstructions: function processingInstructions(name) {
|
|
notImplemented('XML.processingInstructions');
|
|
},
|
|
prependChild: function prependChild(value) {
|
|
notImplemented('XML.prependChild');
|
|
},
|
|
removeNamespace: function removeNamespace(ns) {
|
|
notImplemented('XML.removeNamespace');
|
|
},
|
|
replace: function replace(propertyName, value) {
|
|
var c, x, s, i;
|
|
x = this;
|
|
if (x.kind === 'text' || x.kind === 'comment' || x.kind === 'processing-instruction' || x.kind === 'attribute') {
|
|
return x;
|
|
}
|
|
if (!isXMLType(value)) {
|
|
c = value.toString();
|
|
} else {
|
|
c = value.deepCopy();
|
|
}
|
|
var i = propertyName >>> 0;
|
|
if (String(propertyName) === String(i)) {
|
|
x.replace(propertyName, c);
|
|
return x;
|
|
}
|
|
n = new QName(propertyName);
|
|
i = undefined;
|
|
for (k = x.length() - 1; k >= 0; k--) {
|
|
var v = x.children[k];
|
|
if (n.isAny || v.kind === 'element' && v.name.localName === n.localName && (n.uri === null || v.kind === 'element' && v.name.uri === n.uri)) {
|
|
if (i !== undefined) {
|
|
x.deleteByIndex(String(i));
|
|
}
|
|
i = k;
|
|
}
|
|
}
|
|
if (i !== undefined) {
|
|
x.replace(i.toString(), c);
|
|
}
|
|
return x;
|
|
},
|
|
setChildren: function setChildren(value) {
|
|
notImplemented('XML.setChildren');
|
|
},
|
|
setLocalName: function setLocalName(name) {
|
|
notImplemented('XML.setLocalName');
|
|
},
|
|
setName: function setName(name) {
|
|
notImplemented('XML.setName');
|
|
},
|
|
setNamespace: function setNamespace(ns) {
|
|
notImplemented('XML.setNamespace');
|
|
},
|
|
text: function text() {
|
|
return this.text();
|
|
},
|
|
toXMLString: function () {
|
|
return toXMLString(this);
|
|
},
|
|
notification: function notification() {
|
|
notImplemented('XML.notification');
|
|
},
|
|
setNotification: function setNotification(f) {
|
|
notImplemented('XML.setNotification');
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
};
|
|
XMLListClass = function XMLListClass(runtime, scope, instanceConstructor, baseClass) {
|
|
ASXMLList = function (value) {
|
|
if (!(this instanceof ASXMLList)) {
|
|
return callXMLList(value);
|
|
}
|
|
return constructXMLList(value);
|
|
};
|
|
function callXMLList(v) {
|
|
if (v === null || v === undefined) {
|
|
v = '';
|
|
}
|
|
return toXMLList(v);
|
|
}
|
|
function constructXMLList(val) {
|
|
if (val === null || val === undefined) {
|
|
val = '';
|
|
}
|
|
if (val.isXMLList) {
|
|
var xl = new XMLList();
|
|
xl.append(val);
|
|
return xl;
|
|
}
|
|
return toXMLList(val);
|
|
}
|
|
XMLList = function (targetObject, targetProperty) {
|
|
this.targetObject = targetObject ? targetObject : null;
|
|
this.targetProperty = targetProperty ? targetProperty : null;
|
|
this.children = [];
|
|
};
|
|
var c = new Class('XMLList', ASXMLList, ApplicationDomain.passthroughCallable(ASXMLList));
|
|
c.extend(baseClass);
|
|
var XLp = XMLList.prototype = ASXMLList.prototype;
|
|
XLp.canHandleProperties = true;
|
|
XLp.hasSimpleContent = function hasSimpleContent() {
|
|
if (this.length() === 0) {
|
|
return true;
|
|
} else if (this.length() === 1) {
|
|
return toXML(this).hasSimpleContent();
|
|
}
|
|
var result = true;
|
|
this.children.forEach(function (v) {
|
|
if (v.kind === 'element') {
|
|
result = false;
|
|
}
|
|
});
|
|
return result;
|
|
};
|
|
XLp.asGetProperty = asGetProperty;
|
|
XLp.asGetResolvedStringProperty = asGetResolvedStringPropertyFallback;
|
|
XLp.asSetProperty = asSetProperty;
|
|
XLp.asHasProperty = asHasProperty;
|
|
XLp.asCallProperty = asCallProperty;
|
|
XLp.setProperty = function (mn, v, isMethod) {
|
|
var x, i, r;
|
|
x = this;
|
|
i = mn >>> 0;
|
|
if (String(mn) === String(i)) {
|
|
var targetObject = this.targetObject;
|
|
var targetProperty = this.targetProperty;
|
|
if (targetObject !== null) {
|
|
r = targetObject.resolveValue();
|
|
if (r === null) {
|
|
return;
|
|
}
|
|
} else {
|
|
r = null;
|
|
}
|
|
if (i >= x.length()) {
|
|
if (r && r.isXMLList) {
|
|
if (r.length !== 1) {
|
|
return;
|
|
} else {
|
|
r = r.children[0];
|
|
}
|
|
}
|
|
if (r && r.kind !== 'element') {
|
|
return;
|
|
}
|
|
var y = new XML();
|
|
y.parent = r;
|
|
y.name = x.targetProperty;
|
|
if (targetProperty === null || targetProperty.localName === '*') {
|
|
y.name = null;
|
|
y.kind = 'text';
|
|
} else if (targetProperty.isAttr) {
|
|
var attributeExists = r.getProperty(y.name);
|
|
if (attributeExists.length() > 0) {
|
|
return;
|
|
}
|
|
r.kind = 'attribute';
|
|
} else {
|
|
y.kind = 'element';
|
|
}
|
|
i = x.length();
|
|
if (y.kind !== 'attribute') {
|
|
if (r !== null) {
|
|
if (i > 0) {
|
|
var j = 0;
|
|
while (j < r.length() - 1 && r.children[j] !== x.children[i - 1]) {
|
|
j++;
|
|
}
|
|
} else {
|
|
var j = r.length() - 1;
|
|
}
|
|
r.insert(String(j + 1), y);
|
|
}
|
|
if (v.isXML) {
|
|
y.name = v.name;
|
|
} else if (v.isXMLList) {
|
|
y.name = v.targetProperty;
|
|
}
|
|
}
|
|
x.append(y);
|
|
}
|
|
if (!v.isXML && !v.isXMLList || v.kind === 'text' || v.kind === 'attribute') {
|
|
v = toString(v);
|
|
}
|
|
if (x.children[i].kind === 'attribute') {
|
|
var z = toAttributeName(x.children[i].name);
|
|
x.children[i].parent.setProperty(z, v);
|
|
var attr = x.children[i].parent.getProperty(z);
|
|
x.children[i] = attr.children[0];
|
|
} else if (v.isXMLList) {
|
|
var c = v.deepCopy();
|
|
var parent = x.children[i].parent;
|
|
if (parent !== null) {
|
|
var q;
|
|
parent.children.some(function (v, p) {
|
|
if (v == x.children[i]) {
|
|
q = p;
|
|
return true;
|
|
}
|
|
});
|
|
parent.replace(q, c);
|
|
c.children.forEach(function (v, j) {
|
|
c.children[j] = parent.children[q >>> 0 + j];
|
|
});
|
|
}
|
|
if (c.length() === 0) {
|
|
for (var j = x + 1; j < x.length() - 1; j++) {
|
|
x.children[String(j - 1)] = x.children[j];
|
|
}
|
|
} else {
|
|
for (var j = x.length() - 1; j >= i + 1; j--) {
|
|
x.children[String(j + c.length() - 1)] = x.children[j];
|
|
}
|
|
}
|
|
for (var j = 0; j < c.length(); j++) {
|
|
x.children[i + j] = c.children[j];
|
|
}
|
|
} else if (v.isXML || (k = x.children[i].kind) === 'text' || k === 'comment' || k === 'processing-instruction') {
|
|
var parent = x.children[i].parent;
|
|
if (parent !== null) {
|
|
var q;
|
|
parent.children.some(function (v, p) {
|
|
if (v == x.children[i]) {
|
|
q = p;
|
|
return true;
|
|
}
|
|
});
|
|
parent.replace(q, v);
|
|
var v = parent.children[q];
|
|
}
|
|
if (typeof v === 'string') {
|
|
var t = new XML('text');
|
|
t.parent = x;
|
|
t.value = v;
|
|
x.children[i] = t;
|
|
} else {
|
|
x.children[i] = v;
|
|
}
|
|
} else {
|
|
x.children[i].setProperty('*', v);
|
|
}
|
|
} else if (x.length() <= 1) {
|
|
if (x.length() === 0) {
|
|
r = x.resolveValue();
|
|
if (r === null || r.length() !== 1) {
|
|
return;
|
|
}
|
|
x.append(r);
|
|
}
|
|
x.children[0].setProperty(mn, v);
|
|
}
|
|
};
|
|
XLp.getProperty = function (mn, isMethod) {
|
|
if (isMethod) {
|
|
var resolved = Multiname.isQName(mn) ? mn : this.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags);
|
|
return this[Multiname.getQualifiedName(resolved)];
|
|
}
|
|
var x = this;
|
|
var i = mn >>> 0;
|
|
if (String(mn) === String(i)) {
|
|
return x.children[mn];
|
|
}
|
|
var name = toXMLName(mn);
|
|
var xl = new XMLList(this, name);
|
|
x.children.forEach(function (v, i) {
|
|
var xl2;
|
|
if (v.kind === 'element') {
|
|
xl2 = v.getProperty(mn);
|
|
if (xl2.length() > 0) {
|
|
xl.append(xl2);
|
|
}
|
|
}
|
|
});
|
|
return xl;
|
|
};
|
|
XLp.hasProperty = function (mn, isMethod) {
|
|
if (isMethod) {
|
|
var resolved = Multiname.isQName(mn) ? mn : this.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags);
|
|
return !(!this[Multiname.getQualifiedName(resolved)]);
|
|
}
|
|
var x = this;
|
|
var i = mn >>> 0;
|
|
if (String(mn) === String(i)) {
|
|
return !(!x.children[mn]);
|
|
}
|
|
var name = toXMLName(mn);
|
|
return this.children.some(function (v, i) {
|
|
var xl2 = v.getProperty(mn);
|
|
if (xl2.length() > 0) {
|
|
return true;
|
|
}
|
|
});
|
|
};
|
|
XLp.delete = function (key, isMethod) {
|
|
};
|
|
XLp.append = function (val) {
|
|
if (val.isXMLList) {
|
|
this.targetObject = val.targetObject;
|
|
this.targetProperty = val.targetProperty;
|
|
if (val.length() === 0) {
|
|
return;
|
|
}
|
|
for (var i = 0; i < val.length(); i++) {
|
|
this.children.push(val.children[i]);
|
|
}
|
|
} else if (val.isXML) {
|
|
this.children.push(val);
|
|
}
|
|
};
|
|
XLp.length = function () {
|
|
return this.children.length;
|
|
};
|
|
XLp.resolve = function () {
|
|
var base = this.targetObject.resolveValue();
|
|
if (base === null) {
|
|
return null;
|
|
}
|
|
var target = this.targetObject.getProperty(this.targetProperty);
|
|
if (base.length === 0) {
|
|
notImplemented('XMLList.resolve');
|
|
base.setProperty(this.targetProperty, '');
|
|
target = base.getProperty(this.targetProperty);
|
|
return target;
|
|
}
|
|
};
|
|
XLp.deepCopy = function () {
|
|
var xl = new XMLList();
|
|
this.children.forEach(function (v, i) {
|
|
xl.children[i] = v.deepCopy();
|
|
});
|
|
return xl;
|
|
};
|
|
XLp.descendants = function (name) {
|
|
var xl = new XMLList(null);
|
|
this.children.forEach(function (v, i) {
|
|
if (v.kind === 'element') {
|
|
xl.append(v.descendants(name));
|
|
}
|
|
});
|
|
return xl;
|
|
};
|
|
XLp.resolveValue = function resolveValue() {
|
|
if (this.length() > 0) {
|
|
return this;
|
|
}
|
|
var x = this;
|
|
var name = x.name;
|
|
var targetObject = x.targetObject;
|
|
var targetProperty = x.targetProperty;
|
|
if (targetObject === null || targetProperty === null || name.isAttr || name.isAny) {
|
|
return null;
|
|
}
|
|
var base = targetObject.resolveValue();
|
|
if (base === null) {
|
|
return null;
|
|
}
|
|
var target = base.getProperty(targetProperty);
|
|
if (target.length() === 0) {
|
|
if (base.isXMLList && base.length() > 1) {
|
|
return null;
|
|
}
|
|
base.setProperty(targetProperty, '');
|
|
target = base.getProperty(targetProperty);
|
|
}
|
|
return target;
|
|
};
|
|
XLp.asGetEnumerableKeys = function asGetEnumerableKeys() {
|
|
if (XLp === this) {
|
|
return Object.prototype.asGetEnumerableKeys.call(this);
|
|
}
|
|
var keys = [];
|
|
this.children.forEach(function (v, i) {
|
|
keys.push(i);
|
|
});
|
|
return keys;
|
|
};
|
|
c.native = {
|
|
instance: {
|
|
init: function () {
|
|
}
|
|
}
|
|
};
|
|
XLp.isXMLList = true;
|
|
c.native = {
|
|
static: {},
|
|
instance: {
|
|
toString: function () {
|
|
return toString(this);
|
|
},
|
|
hasOwnProperty: function hasOwnProperty(P) {
|
|
somewhatImplemented('XMLList.hasOwnProperty');
|
|
return this.hasProperty(P);
|
|
},
|
|
propertyIsEnumerable: function propertyIsEnumerable(P) {
|
|
notImplemented('XMLList.propertyIsEnumerable');
|
|
},
|
|
attribute: function attribute(name) {
|
|
return this.getProperty(toAttributeName(name));
|
|
},
|
|
attributes: function attributes() {
|
|
return this.getProperty(toAttributeName('*'));
|
|
},
|
|
child: function child(propertyName) {
|
|
notImplemented('XMLList.child');
|
|
},
|
|
children: function children() {
|
|
var list = new XMLList();
|
|
for (var i = 0; i < this.children.length; i++) {
|
|
var child = this.children[i];
|
|
Array.prototype.push.apply(list.children, child.children);
|
|
}
|
|
return list;
|
|
},
|
|
comments: function comments() {
|
|
var x = this;
|
|
var xl = new XMLList(x, null);
|
|
x.children.forEach(function (v, i) {
|
|
if (v.kind === 'element') {
|
|
xl.append(v.comments());
|
|
}
|
|
});
|
|
return xl;
|
|
},
|
|
contains: function contains(value) {
|
|
for (var i = 0; i < this.children.length; i++) {
|
|
if (this.children[i] === value) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
copy: function copy() {
|
|
return this.deepCopy();
|
|
},
|
|
descendants: function descendants(name) {
|
|
return this.descendants(name === undefined ? '*' : name);
|
|
},
|
|
elements: function elements(name) {
|
|
var x = this;
|
|
var any = false;
|
|
if (name === undefined) {
|
|
name = '*';
|
|
any = true;
|
|
}
|
|
var name = toXMLName(name);
|
|
var xl = new XMLList(x, name);
|
|
x.children.forEach(function (v, i) {
|
|
if (v.kind === 'element') {
|
|
xl.append(v.comments());
|
|
}
|
|
});
|
|
return xl;
|
|
},
|
|
hasComplexContent: function hasComplexContent() {
|
|
notImplemented('XMLList.hasComplexContent');
|
|
},
|
|
hasSimpleContent: function hasSimpleContent() {
|
|
return this.hasSimpleContent();
|
|
},
|
|
length: function length() {
|
|
return this.children.length;
|
|
},
|
|
name: function name() {
|
|
return toXML(this).name;
|
|
},
|
|
normalize: function normalize() {
|
|
notImplemented('XMLList.normalize');
|
|
},
|
|
parent: function parent() {
|
|
notImplemented('XMLList.parent');
|
|
},
|
|
processingInstructions: function processingInstructions(name) {
|
|
notImplemented('XMLList.processingInstructions');
|
|
},
|
|
text: function text() {
|
|
var x = this;
|
|
var xl = new XMLList(x, null);
|
|
x.children.forEach(function (v, i) {
|
|
if (v.kind === 'text' || v.kind === 'element') {
|
|
xl.append(v.text());
|
|
}
|
|
});
|
|
return xl;
|
|
},
|
|
toXMLString: function () {
|
|
return toXMLString(this);
|
|
},
|
|
addNamespace: function addNamespace(ns) {
|
|
notImplemented('XMLList.addNamespace');
|
|
},
|
|
appendChild: function appendChild(child) {
|
|
toXML(this).appendChild(child);
|
|
return this;
|
|
},
|
|
childIndex: function childIndex() {
|
|
notImplemented('XMLList.childIndex');
|
|
},
|
|
inScopeNamespaces: function inScopeNamespaces() {
|
|
notImplemented('XMLList.inScopeNamespaces');
|
|
},
|
|
insertChildAfter: function insertChildAfter(child1, child2) {
|
|
notImplemented('XMLList.insertChildAfter');
|
|
},
|
|
insertChildBefore: function insertChildBefore(child1, child2) {
|
|
notImplemented('XMLList.insertChildBefore');
|
|
},
|
|
nodeKind: function nodeKind() {
|
|
return toXML(this).kind;
|
|
},
|
|
_namespace: function _namespace(prefix, argc) {
|
|
notImplemented('XMLList._namespace');
|
|
},
|
|
localName: function localName() {
|
|
notImplemented('XMLList.localName');
|
|
},
|
|
namespaceDeclarations: function namespaceDeclarations() {
|
|
somewhatImplemented('XMLList.prototype.namespaceDeclarations()');
|
|
return new XMLList();
|
|
},
|
|
prependChild: function prependChild(value) {
|
|
notImplemented('XMLList.prependChild');
|
|
},
|
|
removeNamespace: function removeNamespace(ns) {
|
|
notImplemented('XMLList.removeNamespace');
|
|
},
|
|
replace: function replace(propertyName, value) {
|
|
toXML(this).replace(propertyName, value);
|
|
return this;
|
|
},
|
|
setChildren: function setChildren(value) {
|
|
notImplemented('XMLList.setChildren');
|
|
},
|
|
setLocalName: function setLocalName(name) {
|
|
notImplemented('XMLList.setLocalName');
|
|
},
|
|
setName: function setName(name) {
|
|
notImplemented('XMLList.setName');
|
|
},
|
|
setNamespace: function setNamespace(ns) {
|
|
notImplemented('XMLList.setNamespace');
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
};
|
|
QNameClass = function QNameClass(runtime, scope, instanceConstructor, baseClass) {
|
|
QName = function QName(ns, name, isAttr) {
|
|
if (!(this instanceof QName)) {
|
|
if (name === undefined && ns instanceof QName) {
|
|
return ns;
|
|
} else {
|
|
return new QName(ns, name);
|
|
}
|
|
}
|
|
if (name === undefined) {
|
|
name = ns;
|
|
ns = undefined;
|
|
}
|
|
if (typeof ns === 'string' || ns instanceof QName) {
|
|
ns = new ASNamespace(ns);
|
|
}
|
|
var mn;
|
|
if (name instanceof QName) {
|
|
if (ns === undefined) {
|
|
mn = name.mn;
|
|
} else {
|
|
mn = new Multiname([
|
|
ns
|
|
], name.mn.getName());
|
|
}
|
|
} else if (name instanceof Multiname) {
|
|
if (ns === undefined) {
|
|
if (name.isQName() || name.isAnyName() || name.isAnyNamespace()) {
|
|
mn = name;
|
|
} else {
|
|
mn = new Multiname([
|
|
getDefaultNamespace(scope)
|
|
], name.getName(), name.flags);
|
|
}
|
|
} else {
|
|
mn = new Multiname([
|
|
ns
|
|
], name.getName(), name.flags);
|
|
}
|
|
} else if (name === '*') {
|
|
mn = new Multiname([], null, isAttr ? Multiname.ATTRIBUTE : 0);
|
|
} else if (name === '@*') {
|
|
mn = new Multiname([], null, Multiname.ATTRIBUTE);
|
|
} else {
|
|
ns = ns === undefined ? getDefaultNamespace(scope) : ns;
|
|
if (name === undefined) {
|
|
mn = new Multiname([
|
|
ns
|
|
], '');
|
|
} else {
|
|
mn = new Multiname([
|
|
ns
|
|
], toString(name), isAttr ? Multiname.ATTRIBUTE : 0);
|
|
}
|
|
}
|
|
this.mn = mn;
|
|
this.isAny = mn.isAnyName();
|
|
this.isAnyNamespace = mn.isAnyNamespace();
|
|
this.isAttr = mn.isAttribute();
|
|
};
|
|
var c = new Class('QName', QName, ApplicationDomain.passthroughCallable(QName));
|
|
c.extend(baseClass);
|
|
QNp = QName.prototype;
|
|
defineNonEnumerableGetter(QNp, 'localName', function () {
|
|
if (!this._localName) {
|
|
this._localName = this.isAny ? '*' : this.mn.getName();
|
|
}
|
|
return this._localName;
|
|
});
|
|
defineNonEnumerableGetter(QNp, 'uri', function () {
|
|
if (!this._uri) {
|
|
var ns = this.mn.namespaces[0];
|
|
this._uri = ns && ns.uri ? ns.uri : this.isAny || this.isAnyNamespace ? null : '';
|
|
}
|
|
return this._uri;
|
|
});
|
|
defineNonEnumerableGetter(QNp, 'prefix', function () {
|
|
return this.mn.namespaces[0].prefix;
|
|
});
|
|
defineNonEnumerableSetter(QNp, 'prefix', function (prefix) {
|
|
this.mn.namespaces[0].prefix = prefix;
|
|
});
|
|
QNp.getNamespace = function (isns) {
|
|
if (this.uri === null) {
|
|
throw 'TypeError in QName.prototype.getNamespace()';
|
|
}
|
|
if (!isns) {
|
|
isns = [];
|
|
}
|
|
var ns;
|
|
for (var i = 0; i < isns.length; i++) {
|
|
if (this.uri === isns[i].uri) {
|
|
ns = isns[i];
|
|
}
|
|
}
|
|
if (!ns) {
|
|
ns = ASNamespace.createNamespace(this.uri);
|
|
}
|
|
return ns;
|
|
};
|
|
c.native = {
|
|
static: {},
|
|
instance: {
|
|
localName: {
|
|
get: function localName() {
|
|
return this.localName;
|
|
}
|
|
},
|
|
uri: {
|
|
get: function uri() {
|
|
return this.uri;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
};
|
|
}());
|
|
var AMFUtils = function AMFUtilsClosure() {
|
|
var AMF0_NUMBER_MARKER = 0;
|
|
var AMF0_BOOLEAN_MARKER = 1;
|
|
var AMF0_STRING_MARKER = 2;
|
|
var AMF0_OBJECT_MARKER = 3;
|
|
var AMF0_NULL_MARKER = 5;
|
|
var AMF0_UNDEFINED_MARKER = 6;
|
|
var AMF0_REFERENCE_MARKER = 7;
|
|
var AMF0_ECMA_ARRAY_MARKER = 8;
|
|
var AMF0_OBJECT_END_MARKER = 9;
|
|
var AMF0_STRICT_ARRAY_MARKER = 10;
|
|
var AMF0_DATE_MARKER = 11;
|
|
var AMF0_LONG_STRING_MARKER = 12;
|
|
var AMF0_XML_MARKER = 15;
|
|
var AMF0_TYPED_OBJECT_MARKER = 16;
|
|
var AMF0_AVMPLUS_MARKER = 17;
|
|
function writeString(ba, s) {
|
|
if (s.length > 65535) {
|
|
throw 'AMF short string exceeded';
|
|
}
|
|
if (!s.length) {
|
|
ba.writeByte(0);
|
|
ba.writeByte(0);
|
|
return;
|
|
}
|
|
var bytes = utf8decode(s);
|
|
ba.writeByte(bytes.length >> 8 & 255);
|
|
ba.writeByte(bytes.length & 255);
|
|
for (var i = 0; i < bytes.length; i++) {
|
|
ba.writeByte(bytes[i]);
|
|
}
|
|
}
|
|
function readString(ba) {
|
|
var byteLength = ba.readByte() << 8 | ba.readByte();
|
|
if (!byteLength) {
|
|
return '';
|
|
}
|
|
var buffer = new Uint8Array(byteLength);
|
|
for (var i = 0; i < byteLength; i++) {
|
|
buffer[i] = ba.readByte();
|
|
}
|
|
return utf8encode(buffer);
|
|
}
|
|
function writeDouble(ba, value) {
|
|
var buffer = new ArrayBuffer(8);
|
|
var view = new DataView(buffer);
|
|
view.setFloat64(0, value, false);
|
|
for (var i = 0; i < buffer.byteLength; i++) {
|
|
ba.writeByte(view.getUint8(i));
|
|
}
|
|
}
|
|
function readDouble(ba) {
|
|
var buffer = new ArrayBuffer(8);
|
|
var view = new DataView(buffer);
|
|
for (var i = 0; i < buffer.byteLength; i++) {
|
|
view.setUint8(i, ba.readByte());
|
|
}
|
|
return view.getFloat64(0, false);
|
|
}
|
|
function setAvmProperty(obj, propertyName, value) {
|
|
obj.asSetPublicProperty(propertyName, value);
|
|
}
|
|
var amf0 = {
|
|
write: function (ba, obj) {
|
|
switch (typeof obj) {
|
|
case 'boolean':
|
|
ba.writeByte(AMF0_BOOLEAN_MARKER);
|
|
ba.writeByte(obj ? 1 : 0);
|
|
break;
|
|
case 'number':
|
|
ba.writeByte(AMF0_NUMBER_MARKER);
|
|
writeDouble(ba, obj);
|
|
break;
|
|
case 'undefined':
|
|
ba.writeByte(AMF0_UNDEFINED_MARKER);
|
|
break;
|
|
case 'string':
|
|
ba.writeByte(AMF0_STRING_MARKER);
|
|
writeString(ba, obj);
|
|
break;
|
|
case 'object':
|
|
if (obj === null) {
|
|
ba.writeByte(AMF0_NULL_MARKER);
|
|
} else if (Array.isArray(obj)) {
|
|
ba.writeByte(AMF0_ECMA_ARRAY_MARKER);
|
|
ba.writeByte(obj.length >>> 24 & 255);
|
|
ba.writeByte(obj.length >> 16 & 255);
|
|
ba.writeByte(obj.length >> 8 & 255);
|
|
ba.writeByte(obj.length & 255);
|
|
forEachPublicProperty(obj, function (key, value) {
|
|
writeString(ba, key);
|
|
this.write(ba, value);
|
|
}, this);
|
|
ba.writeByte(0);
|
|
ba.writeByte(0);
|
|
ba.writeByte(AMF0_OBJECT_END_MARKER);
|
|
} else {
|
|
ba.writeByte(AMF0_OBJECT_MARKER);
|
|
forEachPublicProperty(obj, function (key, value) {
|
|
writeString(ba, key);
|
|
this.write(ba, value);
|
|
}, this);
|
|
ba.writeByte(0);
|
|
ba.writeByte(0);
|
|
ba.writeByte(AMF0_OBJECT_END_MARKER);
|
|
}
|
|
return;
|
|
}
|
|
},
|
|
read: function (ba) {
|
|
var marker = ba.readByte();
|
|
switch (marker) {
|
|
case AMF0_NUMBER_MARKER:
|
|
return readDouble(ba);
|
|
case AMF0_BOOLEAN_MARKER:
|
|
return !(!ba.readByte());
|
|
case AMF0_STRING_MARKER:
|
|
return readString(ba);
|
|
case AMF0_OBJECT_MARKER:
|
|
var obj = {};
|
|
while (true) {
|
|
var key = readString(ba);
|
|
if (!key.length)
|
|
break;
|
|
setAvmProperty(obj, key, this.read(ba));
|
|
}
|
|
if (ba.readByte() !== AMF0_OBJECT_END_MARKER) {
|
|
throw 'AMF0 End marker is not found';
|
|
}
|
|
return obj;
|
|
case AMF0_NULL_MARKER:
|
|
return null;
|
|
case AMF0_UNDEFINED_MARKER:
|
|
return undefined;
|
|
case AMF0_ECMA_ARRAY_MARKER:
|
|
var obj = [];
|
|
obj.length = ba.readByte() << 24 | ba.readByte() << 16 | ba.readByte() << 8 | ba.readByte();
|
|
while (true) {
|
|
var key = readString(ba);
|
|
if (!key.length)
|
|
break;
|
|
setAvmProperty(obj, key, this.read(ba));
|
|
}
|
|
if (ba.readByte() !== AMF0_OBJECT_END_MARKER) {
|
|
throw 'AMF0 End marker is not found';
|
|
}
|
|
return obj;
|
|
case AMF0_STRICT_ARRAY_MARKER:
|
|
var obj = [];
|
|
obj.length = ba.readByte() << 24 | ba.readByte() << 16 | ba.readByte() << 8 | ba.readByte();
|
|
for (var i = 0; i < obj.length; i++) {
|
|
obj[i] = this.read(ba);
|
|
}
|
|
return obj;
|
|
case AMF0_AVMPLUS_MARKER:
|
|
return readAmf3Data(ba, {});
|
|
default:
|
|
throw 'AMF0 Unknown marker ' + marker;
|
|
}
|
|
}
|
|
};
|
|
var AMF3_UNDEFINED_MARKER = 0;
|
|
var AMF3_NULL_MARKER = 1;
|
|
var AMF3_FALSE_MARKER = 2;
|
|
var AMF3_TRUE_MARKER = 3;
|
|
var AMF3_INTEGER_MARKER = 4;
|
|
var AMF3_DOUBLE_MARKER = 5;
|
|
var AMF3_STRING_MARKER = 6;
|
|
var AMF3_XML_DOC_MARKER = 7;
|
|
var AMF3_DATE_MARKER = 8;
|
|
var AMF3_ARRAY_MARKER = 9;
|
|
var AMF3_OBJECT_MARKER = 10;
|
|
var AMF3_XML_MARKER = 11;
|
|
var AMF3_BYTEARRAY_MARKER = 12;
|
|
var AMF3_VECTOR_INT_MARKER = 13;
|
|
var AMF3_VECTOR_UINT_MARKER = 14;
|
|
var AMF3_VECTOR_DOUBLE_MARKER = 15;
|
|
var AMF3_VECTOR_OBJECT_MARKER = 16;
|
|
var AMF3_DICTIONARY_MARKER = 17;
|
|
function readU29(ba) {
|
|
var b1 = ba.readByte();
|
|
if ((b1 & 128) === 0) {
|
|
return b1;
|
|
}
|
|
var b2 = ba.readByte();
|
|
if ((b2 & 128) === 0) {
|
|
return (b1 & 127) << 7 | b2;
|
|
}
|
|
var b3 = ba.readByte();
|
|
if ((b3 & 128) === 0) {
|
|
return (b1 & 127) << 14 | (b2 & 127) << 7 | b3;
|
|
}
|
|
var b4 = ba.readByte();
|
|
return (b1 & 127) << 22 | (b2 & 127) << 15 | (b3 & 127) << 8 | b4;
|
|
}
|
|
function writeU29(ba, value) {
|
|
if ((value & 4294967168) === 0) {
|
|
ba.writeByte(value & 127);
|
|
} else if ((value & 4294950912) === 0) {
|
|
ba.writeByte(128 | value >> 7 & 127);
|
|
ba.writeByte(value & 127);
|
|
} else if ((value & 4292870144) === 0) {
|
|
ba.writeByte(128 | value >> 14 & 127);
|
|
ba.writeByte(128 | value >> 7 & 127);
|
|
ba.writeByte(value & 127);
|
|
} else if ((value & 3221225472) === 0) {
|
|
ba.writeByte(128 | value >> 22 & 127);
|
|
ba.writeByte(128 | value >> 15 & 127);
|
|
ba.writeByte(128 | value >> 8 & 127);
|
|
ba.writeByte(value & 255);
|
|
} else {
|
|
throw 'AMF3 U29 range';
|
|
}
|
|
}
|
|
function readUTF8vr(ba, caches) {
|
|
var u29s = readU29(ba);
|
|
if (u29s === 1) {
|
|
return '';
|
|
}
|
|
var stringsCache = caches.stringsCache || (caches.stringsCache = []);
|
|
if ((u29s & 1) === 0) {
|
|
return stringsCache[u29s >> 1];
|
|
}
|
|
var byteLength = u29s >> 1;
|
|
var buffer = new Uint8Array(byteLength);
|
|
for (var i = 0; i < byteLength; i++) {
|
|
buffer[i] = ba.readByte();
|
|
}
|
|
var value = utf8encode(buffer);
|
|
stringsCache.push(value);
|
|
return value;
|
|
}
|
|
function writeUTF8vr(ba, value, caches) {
|
|
if (value === '') {
|
|
ba.writeByte(1);
|
|
return;
|
|
}
|
|
var stringsCache = caches.stringsCache || (caches.stringsCache = []);
|
|
var index = stringsCache.indexOf(value);
|
|
if (index >= 0) {
|
|
writeU29(ba, index << 1);
|
|
return;
|
|
}
|
|
stringsCache.push(value);
|
|
var bytes = utf8decode(value);
|
|
writeU29(ba, 1 | bytes.length << 1);
|
|
for (var i = 0; i < bytes.length; i++) {
|
|
ba.writeByte(bytes[i]);
|
|
}
|
|
}
|
|
function readAmf3Data(ba, caches) {
|
|
var marker = ba.readByte();
|
|
switch (marker) {
|
|
case AMF3_NULL_MARKER:
|
|
return null;
|
|
case AMF3_UNDEFINED_MARKER:
|
|
return undefined;
|
|
case AMF3_FALSE_MARKER:
|
|
return false;
|
|
case AMF3_TRUE_MARKER:
|
|
return true;
|
|
case AMF3_INTEGER_MARKER:
|
|
return readU29(ba);
|
|
case AMF3_DOUBLE_MARKER:
|
|
return readDouble(ba);
|
|
case AMF3_STRING_MARKER:
|
|
return readUTF8vr(ba, caches);
|
|
case AMF3_DATE_MARKER:
|
|
return new Date(readDouble(ba));
|
|
case AMF3_OBJECT_MARKER:
|
|
var u29o = readU29(ba);
|
|
if ((u29o & 1) === 0) {
|
|
return caches.objectsCache[u29o >> 1];
|
|
}
|
|
if ((u29o & 4) !== 0) {
|
|
throw 'AMF3 Traits-Ext is not supported';
|
|
}
|
|
var traits, objectClass;
|
|
if ((u29o & 2) === 0) {
|
|
traits = caches.traitsCache[u29o >> 2];
|
|
objectClass = traits.class;
|
|
} else {
|
|
traits = {};
|
|
var aliasName = readUTF8vr(ba, caches);
|
|
traits.className = aliasName;
|
|
objectClass = aliasName && aliasesCache.names[aliasName];
|
|
traits.class = objectClass;
|
|
traits.isDynamic = (u29o & 8) !== 0;
|
|
traits.members = [];
|
|
var slots = objectClass && objectClass.instanceBindings.slots;
|
|
for (var i = 0, j = u29o >> 4; i < j; i++) {
|
|
var traitName = readUTF8vr(ba, caches);
|
|
var slot = null;
|
|
for (var j = 1; slots && j < slots.length; j++) {
|
|
if (slots[j].name.name === traitName) {
|
|
slot = slots[j];
|
|
break;
|
|
}
|
|
}
|
|
traits.members.push(slot ? Multiname.getQualifiedName(slot.name) : Multiname.getPublicQualifiedName(traitName));
|
|
}
|
|
(caches.traitsCache || (caches.traitsCache = [])).push(traits);
|
|
}
|
|
var obj = objectClass ? objectClass.createInstance() : {};
|
|
(caches.objectsCache || (caches.objectsCache = [])).push(obj);
|
|
for (var i = 0; i < traits.members.length; i++) {
|
|
var value = readAmf3Data(ba, caches);
|
|
obj[traits.members[i]] = value;
|
|
}
|
|
if (traits.isDynamic) {
|
|
while (true) {
|
|
var key = readUTF8vr(ba, caches);
|
|
if (!key.length)
|
|
break;
|
|
var value = readAmf3Data(ba, caches);
|
|
setAvmProperty(obj, key, value);
|
|
}
|
|
}
|
|
return obj;
|
|
case AMF3_ARRAY_MARKER:
|
|
var u29o = readU29(ba);
|
|
if ((u29o & 1) === 0) {
|
|
return caches.objectsCache[u29o >> 1];
|
|
}
|
|
var obj = [];
|
|
(caches.objectsCache || (caches.objectsCache = [])).push(obj);
|
|
var densePortionLength = u29o >> 1;
|
|
while (true) {
|
|
var key = readUTF8vr(ba, caches);
|
|
if (!key.length)
|
|
break;
|
|
var value = readAmf3Data(ba, caches);
|
|
setAvmProperty(obj, key, value);
|
|
}
|
|
for (var i = 0; i < densePortionLength; i++) {
|
|
var value = readAmf3Data(ba, caches);
|
|
setAvmProperty(obj, i, value);
|
|
}
|
|
return obj;
|
|
default:
|
|
throw 'AMF3 Unknown marker ' + marker;
|
|
}
|
|
}
|
|
function writeCachedReference(ba, obj, caches) {
|
|
var objectsCache = caches.objectsCache || (caches.objectsCache = []);
|
|
var index = objectsCache.indexOf(obj);
|
|
if (index < 0) {
|
|
objectsCache.push(obj);
|
|
return false;
|
|
}
|
|
writeU29(ba, index << 1);
|
|
return true;
|
|
}
|
|
function writeAmf3Data(ba, obj, caches) {
|
|
switch (typeof obj) {
|
|
case 'boolean':
|
|
ba.writeByte(obj ? AMF3_TRUE_MARKER : AMF3_FALSE_MARKER);
|
|
break;
|
|
case 'number':
|
|
if (obj === (obj | 0)) {
|
|
ba.writeByte(AMF3_INTEGER_MARKER);
|
|
writeU29(ba, obj);
|
|
} else {
|
|
ba.writeByte(AMF3_DOUBLE_MARKER);
|
|
writeDouble(ba, obj);
|
|
}
|
|
break;
|
|
case 'undefined':
|
|
ba.writeByte(AMF3_UNDEFINED_MARKER);
|
|
break;
|
|
case 'string':
|
|
ba.writeByte(AMF3_STRING_MARKER);
|
|
writeUTF8vr(ba, obj, caches);
|
|
break;
|
|
case 'object':
|
|
if (obj === null) {
|
|
ba.writeByte(AMF3_NULL_MARKER);
|
|
} else if (Array.isArray(obj)) {
|
|
ba.writeByte(AMF3_ARRAY_MARKER);
|
|
if (writeCachedReference(ba, obj, caches))
|
|
break;
|
|
var densePortionLength = 0;
|
|
while (densePortionLength in obj) {
|
|
++densePortionLength;
|
|
}
|
|
writeU29(ba, densePortionLength << 1 | 1);
|
|
forEachPublicProperty(obj, function (i, value) {
|
|
if (isNumeric(i) && i >= 0 && i < densePortionLength) {
|
|
return;
|
|
}
|
|
writeUTF8vr(ba, i, caches);
|
|
writeAmf3Data(ba, value, caches);
|
|
});
|
|
writeUTF8vr(ba, '', caches);
|
|
for (var j = 0; j < densePortionLength; j++) {
|
|
writeAmf3Data(ba, obj[j], caches);
|
|
}
|
|
} else if (obj instanceof Date) {
|
|
ba.writeByte(AMF3_DATE_MARKER);
|
|
if (writeCachedReference(ba, obj, caches))
|
|
break;
|
|
writeU29(ba, 1);
|
|
writeDouble(ba, obj.valueOf());
|
|
} else {
|
|
ba.writeByte(AMF3_OBJECT_MARKER);
|
|
if (writeCachedReference(ba, obj, caches))
|
|
break;
|
|
var isDynamic = true;
|
|
var objectClass = obj.class;
|
|
if (objectClass) {
|
|
isDynamic = !objectClass.classInfo.instanceInfo.isSealed();
|
|
var aliasName = aliasesCache.classes.get(objectClass) || '';
|
|
var traits, traitsCount;
|
|
var traitsCache = caches.traitsCache || (caches.traitsCache = []);
|
|
var traitsInfos = caches.traitsInfos || (caches.traitsInfos = []);
|
|
var traitsRef = traitsCache.indexOf(objectClass);
|
|
if (traitsRef < 0) {
|
|
var slots = objectClass.instanceBindings.slots;
|
|
traits = [];
|
|
var traitsNames = [];
|
|
for (var i = 1; i < slots.length; i++) {
|
|
var slot = slots[i];
|
|
if (!slot.name.getNamespace().isPublic()) {
|
|
continue;
|
|
}
|
|
traits.push(Multiname.getQualifiedName(slot.name));
|
|
traitsNames.push(slot.name.name);
|
|
}
|
|
traitsCache.push(objectClass);
|
|
traitsInfos.push(traits);
|
|
traitsCount = traitsNames.length;
|
|
writeU29(ba, (isDynamic ? 11 : 3) + (traitsCount << 4));
|
|
writeUTF8vr(ba, aliasName, caches);
|
|
for (var i = 0; i < traitsCount; i++) {
|
|
writeUTF8vr(ba, traitsNames[i], caches);
|
|
}
|
|
} else {
|
|
traits = traitsInfos[traitsRef];
|
|
traitsCount = traits.length;
|
|
writeU29(ba, 1 + (traitsRef << 2));
|
|
}
|
|
for (var i = 0; i < traitsCount; i++) {
|
|
writeAmf3Data(ba, obj[traits[i]], caches);
|
|
}
|
|
} else {
|
|
writeU29(ba, 11);
|
|
writeUTF8vr(ba, '', caches);
|
|
}
|
|
if (isDynamic) {
|
|
forEachPublicProperty(obj, function (i, value) {
|
|
writeUTF8vr(ba, i, caches);
|
|
writeAmf3Data(ba, value, caches);
|
|
});
|
|
writeUTF8vr(ba, '', caches);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
var aliasesCache = {
|
|
classes: new WeakMap(),
|
|
names: Object.create(null)
|
|
};
|
|
var amf3 = {
|
|
write: function (ba, obj) {
|
|
writeAmf3Data(ba, obj, {});
|
|
},
|
|
read: function (ba) {
|
|
return readAmf3Data(ba, {});
|
|
}
|
|
};
|
|
return {
|
|
encodings: [
|
|
amf0,
|
|
null,
|
|
null,
|
|
amf3
|
|
],
|
|
aliasesCache: aliasesCache
|
|
};
|
|
}();
|
|
function ProxyClass(runtime, scope, instanceConstructor, baseClass) {
|
|
function ProxyConstructor() {
|
|
somewhatImplemented('Proxy');
|
|
}
|
|
var c = new Class('Proxy', ProxyConstructor, ApplicationDomain.coerceCallable(ProxyConstructor));
|
|
c.extendBuiltin(baseClass);
|
|
return c;
|
|
}
|
|
var proxyTrapQns = {
|
|
'getProperty': null,
|
|
'setProperty': null,
|
|
'hasProperty': null,
|
|
'callProperty': null
|
|
};
|
|
for (var name in proxyTrapQns) {
|
|
proxyTrapQns[name] = VM_OPEN_METHOD_PREFIX + Multiname.getQualifiedName(new Multiname([
|
|
ASNamespace.PROXY
|
|
], name));
|
|
}
|
|
function isProxyObject(obj) {
|
|
return obj[VM_IS_PROXY];
|
|
}
|
|
function nameFromQualifiedName(qn) {
|
|
if (isNumeric(qn)) {
|
|
return qn;
|
|
}
|
|
var mn = Multiname.fromQualifiedName(qn);
|
|
if (mn === undefined) {
|
|
return undefined;
|
|
}
|
|
return mn.name;
|
|
}
|
|
function hasNonProxyingCaller() {
|
|
var caller = arguments.callee;
|
|
var maxDepth = 5;
|
|
var domain;
|
|
for (var i = 0; i < maxDepth && caller; i++) {
|
|
if (caller === nonProxyingHasProperty) {
|
|
return true;
|
|
}
|
|
caller = caller.caller;
|
|
}
|
|
return false;
|
|
}
|
|
function installProxyClassWrapper(cls) {
|
|
var TRACE_PROXY = false;
|
|
if (TRACE_PROXY) {
|
|
print('proxy wrapping, class: ' + cls);
|
|
}
|
|
var instanceConstructor = cls.instanceConstructor;
|
|
function construct() {
|
|
if (TRACE_PROXY) {
|
|
print('proxy create, class: ' + cls);
|
|
}
|
|
var target = Object.create(instanceConstructor.prototype);
|
|
var proxy = Proxy.create({
|
|
get: function (o, qn) {
|
|
if (qn === VM_IS_PROXY) {
|
|
TRACE_PROXY && print('proxy check');
|
|
return true;
|
|
}
|
|
if (qn === VM_CALL_PROXY) {
|
|
TRACE_PROXY && print('proxy get caller');
|
|
return function apply(mn, receiver, args) {
|
|
receiver = receiver ? target : null;
|
|
if (TRACE_PROXY) {
|
|
print('proxy call, class: ' + target.class + ', mn: ' + mn + 'hasNonProxyingCallerr: ' + hasNonProxyingCaller());
|
|
}
|
|
var resolved = Multiname.isQName(mn) ? mn : target.resolveMultinameProperty(mn.namespaces, mn.name, mn.flags);
|
|
var qn = resolved ? Multiname.getQualifiedName(resolved) : Multiname.getPublicQualifiedName(mn.name);
|
|
if (!nameInTraits(target, qn)) {
|
|
return target[proxyTrapQns.callProperty](mn.name, args);
|
|
}
|
|
if (TRACE_PROXY) {
|
|
TRACE_PROXY && print('> proxy pass through ' + resolved);
|
|
}
|
|
if (target.asOpenMethods && target.asOpenMethods[qn]) {
|
|
return target.asOpenMethods[qn].apply(o, args);
|
|
}
|
|
return undefined;
|
|
};
|
|
}
|
|
if (TRACE_PROXY) {
|
|
print('proxy get, class: ' + target.class + ', qn: ' + qn + 'hasNonProxyingCallerr: ' + hasNonProxyingCaller());
|
|
}
|
|
if (!hasNonProxyingCaller()) {
|
|
var name = nameFromQualifiedName(qn);
|
|
if (name !== undefined && !nameInTraits(target, qn)) {
|
|
return target[proxyTrapQns.getProperty](name);
|
|
}
|
|
}
|
|
if (target.asOpenMethods && target.asOpenMethods[qn]) {
|
|
return bindSafely(target.asOpenMethods[qn], o);
|
|
}
|
|
TRACE_PROXY && print('> proxy pass through ' + qn);
|
|
return target[qn];
|
|
},
|
|
set: function (o, qn, value) {
|
|
if (TRACE_PROXY) {
|
|
print('proxy set, class: ' + target.class + ', qn: ' + qn + 'hasNonProxyingCallerr: ' + hasNonProxyingCaller());
|
|
}
|
|
if (!hasNonProxyingCaller()) {
|
|
var name = nameFromQualifiedName(qn);
|
|
if (name !== undefined && !nameInTraits(target, qn)) {
|
|
target[proxyTrapQns.setProperty](name, value);
|
|
return;
|
|
}
|
|
}
|
|
TRACE_PROXY && print('> proxy pass through ' + qn);
|
|
target[qn] = value;
|
|
},
|
|
has: function (qn) {
|
|
if (TRACE_PROXY) {
|
|
print('proxy has, class: ' + target.class + ', qn: ' + qn + 'hasNonProxyingCallerr: ' + hasNonProxyingCaller());
|
|
}
|
|
if (!hasNonProxyingCaller()) {
|
|
var name = nameFromQualifiedName(qn);
|
|
if (name !== undefined && !nameInTraits(target, qn)) {
|
|
return target[proxyTrapQns.hasProperty](name);
|
|
}
|
|
}
|
|
return qn in target;
|
|
},
|
|
hasOwn: function (qn) {
|
|
if (TRACE_PROXY) {
|
|
print('proxy hasOwn, class: ' + target.class + ', qn: ' + qn + 'hasNonProxyingCallerr: ' + hasNonProxyingCaller());
|
|
}
|
|
if (!hasNonProxyingCaller()) {
|
|
var name = nameFromQualifiedName(qn);
|
|
if (name !== undefined && !nameInTraits(target, qn)) {
|
|
return target[proxyTrapQns.hasProperty](name);
|
|
}
|
|
}
|
|
TRACE_PROXY && print('> proxy pass through ' + qn);
|
|
return !(!Object.getOwnPropertyDescriptor(target, qn));
|
|
},
|
|
enumerate: function () {
|
|
notImplemented('enumerate');
|
|
},
|
|
keys: function () {
|
|
notImplemented('keys');
|
|
}
|
|
}, instanceConstructor.prototype);
|
|
instanceConstructor.apply(proxy, sliceArguments(arguments, 0));
|
|
return proxy;
|
|
}
|
|
cls.instanceConstructor = construct;
|
|
}
|
|
function DictionaryClass(domain, scope, instanceConstructor, baseClass) {
|
|
function ASDictionary(weakKeys) {
|
|
this.weakKeys = weakKeys;
|
|
this.map = new WeakMap();
|
|
if (!weakKeys) {
|
|
this.keys = [];
|
|
}
|
|
this.primitiveMap = createEmptyObject();
|
|
}
|
|
var c = new Class('Dictionary', ASDictionary, ApplicationDomain.passthroughCallable(ASDictionary));
|
|
c.extendNative(baseClass, ASDictionary);
|
|
function makePrimitiveKey(key) {
|
|
if (typeof key === 'string' || typeof key === 'number') {
|
|
return key;
|
|
}
|
|
return undefined;
|
|
}
|
|
var prototype = ASDictionary.prototype;
|
|
defineNonEnumerableProperty(prototype, 'asGetProperty', function asGetProperty(namespaces, name, flags, isMethod) {
|
|
var key = makePrimitiveKey(name);
|
|
if (key !== undefined) {
|
|
return this.primitiveMap[key];
|
|
}
|
|
return this.map.get(Object(name));
|
|
});
|
|
defineNonEnumerableProperty(prototype, 'asGetResolvedStringProperty', asGetResolvedStringPropertyFallback);
|
|
defineNonEnumerableProperty(prototype, 'asSetProperty', function asSetProperty(namespaces, name, flags, value) {
|
|
var key = makePrimitiveKey(name);
|
|
if (key !== undefined) {
|
|
this.primitiveMap[key] = value;
|
|
return;
|
|
}
|
|
this.map.set(Object(name), value);
|
|
if (!this.weakKeys && this.keys.indexOf(name) < 0) {
|
|
this.keys.push(name);
|
|
}
|
|
});
|
|
defineNonEnumerableProperty(prototype, 'asCallProperty', function asCallProperty(namespaces, name, flags, isLex, args) {
|
|
notImplemented('asCallProperty');
|
|
});
|
|
defineNonEnumerableProperty(prototype, 'asHasProperty', function asHasProperty(namespaces, name, flags, nonProxy) {
|
|
var key = makePrimitiveKey(name);
|
|
if (key !== undefined) {
|
|
return key in this.primitiveMap;
|
|
}
|
|
return this.map.has(Object(name));
|
|
});
|
|
defineNonEnumerableProperty(prototype, 'asDeleteProperty', function asDeleteProperty(namespaces, name, flags) {
|
|
var key = makePrimitiveKey(name);
|
|
if (key !== undefined) {
|
|
delete this.primitiveMap[key];
|
|
}
|
|
this.map.delete(Object(name));
|
|
var i;
|
|
if (!this.weakKeys && (i = this.keys.indexOf(name)) >= 0) {
|
|
this.keys.splice(i, 1);
|
|
}
|
|
return true;
|
|
});
|
|
defineNonEnumerableProperty(prototype, 'asGetEnumerableKeys', function () {
|
|
if (prototype === this) {
|
|
return Object.prototype.asGetEnumerableKeys.call(this);
|
|
}
|
|
var primitiveMapKeys = [];
|
|
for (var k in this.primitiveMap) {
|
|
primitiveMapKeys.push(k);
|
|
}
|
|
if (this.weakKeys) {
|
|
return primitiveMapKeys;
|
|
}
|
|
return primitiveMapKeys.concat(this.keys);
|
|
});
|
|
c.native = {
|
|
instance: {
|
|
init: function () {
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
}
|
|
function debugBreak(message) {
|
|
debugger;
|
|
print('\x1b[91mdebugBreak: ' + message + '\x1b[0m');
|
|
}
|
|
var NativeASNamespace;
|
|
var natives = function () {
|
|
var C = ApplicationDomain.passthroughCallable;
|
|
var CC = ApplicationDomain.constructingCallable;
|
|
function ObjectClass(applicationDomain, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('Object', Object, C(Object));
|
|
c.native = {
|
|
instance: {
|
|
isPrototypeOf: Object.prototype.isPrototypeOf,
|
|
hasOwnProperty: function (name) {
|
|
if (name === undefined) {
|
|
return false;
|
|
}
|
|
name = Multiname.getPublicQualifiedName(name);
|
|
if (Object.prototype.hasOwnProperty.call(this, name)) {
|
|
return true;
|
|
}
|
|
return Object.getPrototypeOf(this).hasOwnProperty(name);
|
|
},
|
|
propertyIsEnumerable: function (name) {
|
|
if (name === undefined) {
|
|
return false;
|
|
}
|
|
name = Multiname.getPublicQualifiedName(name);
|
|
return Object.prototype.propertyIsEnumerable.call(this, name);
|
|
}
|
|
},
|
|
static: {
|
|
_setPropertyIsEnumerable: function _setPropertyIsEnumerable(obj, name, isEnum) {
|
|
name = Multiname.getPublicQualifiedName(name);
|
|
var descriptor = Object.getOwnPropertyDescriptor(obj, name);
|
|
descriptor.enumerable = false;
|
|
Object.defineProperty(obj, name, descriptor);
|
|
}
|
|
}
|
|
};
|
|
c.dynamicPrototype = c.traitsPrototype = Object.prototype;
|
|
c.setDefaultProperties();
|
|
c.defaultValue = null;
|
|
c.coerce = function (value) {
|
|
return asCoerceObject(value);
|
|
};
|
|
c.isInstanceOf = function (value) {
|
|
if (value === null) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
c.isInstance = function (value) {
|
|
if (value === null || value === undefined) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
return c;
|
|
}
|
|
function ClassClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = Class;
|
|
c.debugName = 'Class';
|
|
c.prototype.extendBuiltin.call(c, baseClass);
|
|
c.coerce = function (value) {
|
|
return value;
|
|
};
|
|
c.isInstanceOf = function (value) {
|
|
return true;
|
|
};
|
|
c.isInstance = function (value) {
|
|
return value instanceof c.instanceConstructor;
|
|
};
|
|
return c;
|
|
}
|
|
function BooleanClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('Boolean', Boolean, C(Boolean));
|
|
c.extendBuiltin(baseClass);
|
|
c.native = {
|
|
instance: {
|
|
toString: Boolean.prototype.toString,
|
|
valueOf: Boolean.prototype.valueOf
|
|
}
|
|
};
|
|
c.coerce = Boolean;
|
|
c.isInstanceOf = function (value) {
|
|
return typeof value === 'boolean' || value instanceof Boolean;
|
|
};
|
|
c.isInstance = function (value) {
|
|
if (typeof value === 'boolean' || value instanceof Boolean) {
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
return c;
|
|
}
|
|
function FunctionClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('Function', Function, C(Function));
|
|
c.extendBuiltin(baseClass);
|
|
c.native = {
|
|
instance: {
|
|
prototype: {
|
|
get: function () {
|
|
return this.prototype;
|
|
},
|
|
set: function (p) {
|
|
this.prototype = p;
|
|
}
|
|
},
|
|
length: {
|
|
get: function () {
|
|
if (this.hasOwnProperty(VM_LENGTH)) {
|
|
return this.asLength;
|
|
}
|
|
return this.length;
|
|
}
|
|
},
|
|
call: Function.prototype.call,
|
|
apply: Function.prototype.apply
|
|
}
|
|
};
|
|
c.coerce = function (value) {
|
|
return value;
|
|
};
|
|
c.isInstanceOf = function (value) {
|
|
return typeof value === 'function';
|
|
};
|
|
c.isInstance = function (value) {
|
|
return typeof value === 'function';
|
|
};
|
|
return c;
|
|
}
|
|
function MethodClosure($this, fn) {
|
|
var bound = bindSafely(fn, $this);
|
|
defineNonEnumerableProperty(this, 'call', bound.call.bind(bound));
|
|
defineNonEnumerableProperty(this, 'apply', bound.apply.bind(bound));
|
|
}
|
|
MethodClosure.prototype = {
|
|
toString: function () {
|
|
return 'function Function() {}';
|
|
}
|
|
};
|
|
function MethodClosureClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('MethodClosure', MethodClosure);
|
|
c.extendBuiltin(baseClass);
|
|
return c;
|
|
}
|
|
function StringClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('String', String, C(String));
|
|
c.extendBuiltin(baseClass);
|
|
var Sp = String.prototype;
|
|
c.native = {
|
|
instance: {
|
|
length: {
|
|
get: function () {
|
|
return this.length;
|
|
}
|
|
},
|
|
indexOf: Sp.indexOf,
|
|
lastIndexOf: Sp.lastIndexOf,
|
|
charAt: Sp.charAt,
|
|
charCodeAt: Sp.charCodeAt,
|
|
concat: Sp.concat,
|
|
localeCompare: Sp.localeCompare,
|
|
match: function (re) {
|
|
if (re === void 0 || re === null) {
|
|
return null;
|
|
} else {
|
|
if (re instanceof RegExp && re.global) {
|
|
var matches = [], m;
|
|
while (m = re.exec(this)) {
|
|
matches.push(m[0]);
|
|
}
|
|
return matches;
|
|
}
|
|
if (!(re instanceof RegExp) && !(typeof re === 'string')) {
|
|
re = String(re);
|
|
}
|
|
return this.match(re);
|
|
}
|
|
},
|
|
replace: Sp.replace,
|
|
search: function (re) {
|
|
if (re === void 0) {
|
|
return -1;
|
|
} else {
|
|
return this.search(re);
|
|
}
|
|
},
|
|
slice: Sp.slice,
|
|
split: Sp.split,
|
|
substr: Sp.substr,
|
|
substring: Sp.substring,
|
|
toLowerCase: Sp.toLowerCase,
|
|
toLocaleLowerCase: Sp.toLocaleLowerCase,
|
|
toUpperCase: function () {
|
|
var str = Sp.toUpperCase.apply(this);
|
|
var str = str.replace(/\u039C/g, String.fromCharCode(181));
|
|
return str;
|
|
},
|
|
toLocaleUpperCase: function () {
|
|
var str = Sp.toLocaleUpperCase.apply(this);
|
|
var str = str.replace(/\u039C/g, String.fromCharCode(181));
|
|
return str;
|
|
},
|
|
toString: Sp.toString,
|
|
valueOf: Sp.valueOf
|
|
},
|
|
static: String
|
|
};
|
|
c.isInstance = function (value) {
|
|
return value !== null && value !== undefined && typeof value.valueOf() === 'string';
|
|
};
|
|
c.coerce = function (value) {
|
|
if (value === null || value === undefined) {
|
|
return null;
|
|
}
|
|
return String(value);
|
|
};
|
|
c.isInstanceOf = function (value) {
|
|
return Object(value) instanceof String;
|
|
};
|
|
c.isInstance = function (value) {
|
|
return Object(value) instanceof String;
|
|
};
|
|
return c;
|
|
}
|
|
function VectorClass(domain, scope, instanceConstructor, baseClass) {
|
|
return createVectorClass(undefined, baseClass);
|
|
}
|
|
function ObjectVectorClass(domain, scope, instanceConstructor, baseClass) {
|
|
return createVectorClass(domain.getClass('Object'), baseClass);
|
|
}
|
|
function IntVectorClass(domain, scope, instanceConstructor, baseClass) {
|
|
return createVectorClass(domain.getClass('int'), baseClass);
|
|
}
|
|
function UIntVectorClass(domain, scope, instanceConstructor, baseClass) {
|
|
return createVectorClass(domain.getClass('uint'), baseClass);
|
|
}
|
|
function DoubleVectorClass(domain, scope, instanceConstructor, baseClass) {
|
|
return createVectorClass(domain.getClass('Number'), baseClass);
|
|
}
|
|
function createVectorClass(type, baseClass) {
|
|
var V;
|
|
if (type) {
|
|
var className = 'Vector$' + type.classInfo.instanceInfo.name.name;
|
|
switch (className) {
|
|
case 'Vector$int':
|
|
V = Int32Vector;
|
|
break;
|
|
case 'Vector$uint':
|
|
V = Uint32Vector;
|
|
break;
|
|
case 'Vector$Number':
|
|
V = Float64Vector;
|
|
break;
|
|
case 'Vector$Object':
|
|
V = GenericVector;
|
|
break;
|
|
default:
|
|
unexpected();
|
|
break;
|
|
}
|
|
} else {
|
|
V = GenericVector.applyType(null);
|
|
}
|
|
var Vp = V.prototype;
|
|
var cls = new Class(className, V, C(V.callable));
|
|
if (V === GenericVector) {
|
|
cls.applyType = function (type) {
|
|
return cls;
|
|
};
|
|
}
|
|
cls.extendWrapper(baseClass, V);
|
|
cls.native = {
|
|
instance: {
|
|
fixed: {
|
|
get: function () {
|
|
return this._fixed;
|
|
},
|
|
set: function (v) {
|
|
this._fixed = v;
|
|
}
|
|
},
|
|
length: {
|
|
get: function () {
|
|
return this.length;
|
|
},
|
|
set: function setLength(length) {
|
|
this.length = length;
|
|
}
|
|
},
|
|
push: Vp.push,
|
|
pop: Vp.pop,
|
|
shift: Vp.shift,
|
|
unshift: Vp.unshift,
|
|
_reverse: Vp.reverse,
|
|
_filter: Vp.filter,
|
|
_map: Vp.map,
|
|
newThisType: function newThisType() {
|
|
return new cls.instanceConstructor();
|
|
},
|
|
_spliceHelper: function _spliceHelper(insertPoint, insertCount, deleteCount, args, offset) {
|
|
return this._spliceHelper(insertPoint, insertCount, deleteCount, args, offset);
|
|
}
|
|
},
|
|
static: {
|
|
_some: function (o, callback, thisObject) {
|
|
return o.some(callback, thisObject);
|
|
},
|
|
_every: function (o, callback, thisObject) {
|
|
return o.every(callback, thisObject);
|
|
},
|
|
_forEach: function (o, callback, thisObject) {
|
|
return o.forEach(callback, thisObject);
|
|
},
|
|
_sort: arraySort
|
|
}
|
|
};
|
|
cls.vectorType = type;
|
|
cls.coerce = function (value) {
|
|
return value;
|
|
};
|
|
cls.isInstanceOf = function (value) {
|
|
return true;
|
|
};
|
|
cls.isInstance = function (value) {
|
|
if (value === null || typeof value !== 'object') {
|
|
return false;
|
|
}
|
|
if (!this.instanceConstructor.vectorType && value.class.vectorType) {
|
|
return true;
|
|
}
|
|
return this.instanceConstructor.prototype.isPrototypeOf(value);
|
|
};
|
|
return cls;
|
|
}
|
|
function NumberClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('Number', Number, C(Number));
|
|
c.extendBuiltin(baseClass);
|
|
c.native = {
|
|
instance: Number.prototype
|
|
};
|
|
c.defaultValue = Number(0);
|
|
c.isInstance = function (value) {
|
|
return value !== null && value !== undefined && typeof value.valueOf() === 'number';
|
|
};
|
|
c.coerce = Number;
|
|
c.isInstanceOf = function (value) {
|
|
return Object(value) instanceof Number;
|
|
};
|
|
c.isInstance = function (value) {
|
|
return Object(value) instanceof Number;
|
|
};
|
|
return c;
|
|
}
|
|
function Int(x) {
|
|
return x | 0;
|
|
}
|
|
function boxedInt(x) {
|
|
return Object(x | 0);
|
|
}
|
|
function intClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('int', boxedInt, C(Int));
|
|
c.extendBuiltin(baseClass);
|
|
c.defaultValue = 0;
|
|
c.coerce = Int;
|
|
c.isInstanceOf = function (value) {
|
|
return false;
|
|
};
|
|
c.isInstance = function (value) {
|
|
if (value instanceof Number) {
|
|
value = value.valueOf();
|
|
}
|
|
return (value | 0) === value;
|
|
};
|
|
return c;
|
|
}
|
|
function Uint(x) {
|
|
return x >>> 0;
|
|
}
|
|
function boxedUint(x) {
|
|
return Object(x >>> 0);
|
|
}
|
|
function uintClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('uint', boxedUint, C(Uint));
|
|
c.extend(baseClass);
|
|
c.defaultValue = 0;
|
|
c.isInstanceOf = function (value) {
|
|
return false;
|
|
};
|
|
c.isInstance = function (value) {
|
|
if (value instanceof Number) {
|
|
value = value.valueOf();
|
|
}
|
|
return value >>> 0 === value;
|
|
};
|
|
c.coerce = Uint;
|
|
return c;
|
|
}
|
|
function MathClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('Math');
|
|
c.native = {
|
|
static: Math
|
|
};
|
|
return c;
|
|
}
|
|
function DateClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('Date', Date, C(Date));
|
|
c.extendBuiltin(baseClass);
|
|
c.native = {
|
|
instance: Date.prototype,
|
|
static: Date
|
|
};
|
|
return c;
|
|
}
|
|
function makeErrorClass(name) {
|
|
var ErrorDefinition = {
|
|
__glue__: {
|
|
script: {
|
|
instance: {
|
|
message: 'public message',
|
|
name: 'public name'
|
|
}
|
|
},
|
|
native: {
|
|
instance: {
|
|
getStackTrace: function () {
|
|
somewhatImplemented('Error.getStackTrace()');
|
|
return AVM2.getStackTrace();
|
|
}
|
|
},
|
|
static: {
|
|
getErrorMessage: getErrorMessage
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return function (runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class(name, instanceConstructor);
|
|
c.extend(baseClass);
|
|
if (name === 'Error') {
|
|
c.link(ErrorDefinition);
|
|
c.linkNatives(ErrorDefinition);
|
|
}
|
|
return c;
|
|
};
|
|
}
|
|
function RegExpClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('RegExp', XRegExp, C(XRegExp));
|
|
c.extendBuiltin(baseClass);
|
|
RegExpClass.exec = function exec() {
|
|
var result = this.exec.apply(this, arguments);
|
|
if (!result) {
|
|
return result;
|
|
}
|
|
var keys = Object.keys(result);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var k = keys[i];
|
|
if (!isNumeric(k)) {
|
|
if (result[k] === undefined) {
|
|
result[k] = '';
|
|
}
|
|
}
|
|
}
|
|
publicizeProperties(result);
|
|
return result;
|
|
};
|
|
RegExpClass.test = function test() {
|
|
return this.exec.apply(this, arguments) !== null;
|
|
};
|
|
c.native = {
|
|
instance: {
|
|
global: {
|
|
get: function () {
|
|
return this.global;
|
|
}
|
|
},
|
|
source: {
|
|
get: function () {
|
|
return this.source;
|
|
}
|
|
},
|
|
ignoreCase: {
|
|
get: function () {
|
|
return this.ignoreCase;
|
|
}
|
|
},
|
|
multiline: {
|
|
get: function () {
|
|
return this.multiline;
|
|
}
|
|
},
|
|
lastIndex: {
|
|
get: function () {
|
|
return this.lastIndex;
|
|
},
|
|
set: function (i) {
|
|
this.lastIndex = i;
|
|
}
|
|
},
|
|
dotall: {
|
|
get: function () {
|
|
return this.dotall;
|
|
}
|
|
},
|
|
extended: {
|
|
get: function () {
|
|
return this.extended;
|
|
}
|
|
},
|
|
exec: RegExpClass.exec,
|
|
test: RegExpClass.test
|
|
}
|
|
};
|
|
return c;
|
|
}
|
|
function NamespaceClass(runtime, scope, instanceConstructor, baseClass) {
|
|
NativeASNamespace = function NativeASNamespace(prefixValue, uriValue) {
|
|
if (uriValue === undefined) {
|
|
uriValue = prefixValue;
|
|
prefixValue = undefined;
|
|
}
|
|
var prefix, uri;
|
|
if (prefixValue === undefined) {
|
|
if (uriValue === undefined) {
|
|
prefix = '';
|
|
uri = '';
|
|
} else if (typeof uriValue === 'object') {
|
|
prefix = uriValue.prefix;
|
|
if (uriValue instanceof ASNamespace) {
|
|
uri = uriValue.uri;
|
|
} else if (uriValue instanceof QName) {
|
|
uri = uriValue.uri;
|
|
}
|
|
} else {
|
|
uri = uriValue + '';
|
|
if (uri === '') {
|
|
prefix = '';
|
|
} else {
|
|
prefix = undefined;
|
|
}
|
|
}
|
|
} else {
|
|
if (typeof uriValue === 'object' && uriValue instanceof QName && uriValue.uri !== null) {
|
|
uri = uriValue.uri;
|
|
} else {
|
|
uri = uriValue + '';
|
|
}
|
|
if (uri === '') {
|
|
if (prefixValue === undefined || prefixValue + '' === '') {
|
|
prefix = '';
|
|
} else {
|
|
throw 'type error';
|
|
}
|
|
} else if (prefixValue === undefined || prefixValue === '') {
|
|
prefix = undefined;
|
|
} else if (false && !isXMLName(prefixValue)) {
|
|
prefix = undefined;
|
|
} else {
|
|
prefix = prefixValue + '';
|
|
}
|
|
}
|
|
return ASNamespace.createNamespace(uri, prefix);
|
|
};
|
|
var c = new Class('Namespace', NativeASNamespace, C(NativeASNamespace));
|
|
c.extendNative(baseClass, ASNamespace);
|
|
var Np = ASNamespace.prototype;
|
|
c.native = {
|
|
instance: {
|
|
prefix: {
|
|
get: Np.getPrefix
|
|
},
|
|
uri: {
|
|
get: Np.getURI
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
}
|
|
function JSONClass(runtime, scope, instanceConstructor, baseClass) {
|
|
function transformJSValueToAS(value) {
|
|
if (typeof value !== 'object') {
|
|
return value;
|
|
}
|
|
var keys = Object.keys(value);
|
|
var result = value instanceof Array ? [] : {};
|
|
for (var i = 0; i < keys.length; i++) {
|
|
result.asSetPublicProperty(keys[i], transformJSValueToAS(value[keys[i]]));
|
|
}
|
|
return result;
|
|
}
|
|
function transformASValueToJS(value) {
|
|
if (typeof value !== 'object') {
|
|
return value;
|
|
}
|
|
var keys = Object.keys(value);
|
|
var result = value instanceof Array ? [] : {};
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
var jsKey = key;
|
|
if (!isNumeric(key)) {
|
|
jsKey = Multiname.getNameFromPublicQualifiedName(key);
|
|
}
|
|
result[jsKey] = transformASValueToJS(value[key]);
|
|
}
|
|
return result;
|
|
}
|
|
function ASJSON() {
|
|
}
|
|
var c = new Class('JSON', ASJSON, C(ASJSON));
|
|
c.extend(baseClass);
|
|
c.native = {
|
|
static: {
|
|
parseCore: function parseCore(text) {
|
|
return transformJSValueToAS(JSON.parse(text));
|
|
},
|
|
stringifySpecializedToString: function stringifySpecializedToString(value, replacerArray, replacerFunction, gap) {
|
|
return JSON.stringify(transformASValueToJS(value), replacerFunction, gap);
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
}
|
|
function CapabilitiesClass(runtime, scope, instanceConstructor, baseClass) {
|
|
function Capabilities() {
|
|
}
|
|
var c = new Class('Capabilities', Capabilities, C(Capabilities));
|
|
c.extend(baseClass);
|
|
c.native = {
|
|
static: {
|
|
playerType: {
|
|
get: function () {
|
|
return 'AVMPlus';
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
}
|
|
function FileClass(runtime, scope, instanceConstructor, baseClass) {
|
|
function File() {
|
|
}
|
|
var c = new Class('File', File, C(File));
|
|
c.extend(baseClass);
|
|
c.native = {
|
|
static: {
|
|
exists: function (filename) {
|
|
notImplemented('File.exists');
|
|
return false;
|
|
},
|
|
read: function (filename) {
|
|
return snarf(filename);
|
|
},
|
|
write: function (filename, data) {
|
|
notImplemented('File.write');
|
|
return true;
|
|
},
|
|
readByteArray: function (filename) {
|
|
var ByteArrayClass = AVM2.currentDomain().getClass('flash.utils.ByteArray');
|
|
var data = ByteArrayClass.createInstance();
|
|
data.writeRawBytes(snarf(filename, 'binary'));
|
|
return data;
|
|
},
|
|
writeByteArray: function (filename, bytes) {
|
|
write('bin/' + filename, bytes.getBytes());
|
|
return true;
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
}
|
|
function ShumwayClass(runtime, scope, instanceConstructor, baseClass) {
|
|
function Shumway() {
|
|
}
|
|
var c = new Class('Shumway', Shumway, C(Shumway));
|
|
c.extend(baseClass);
|
|
c.native = {
|
|
static: {
|
|
info: function (x) {
|
|
console.info(x);
|
|
},
|
|
json: function (x) {
|
|
return JSON.stringify(x);
|
|
},
|
|
eval: function (x) {
|
|
return eval(x);
|
|
},
|
|
debugger: function (x) {
|
|
debugger;
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
}
|
|
function constant(x) {
|
|
return function () {
|
|
return x;
|
|
};
|
|
}
|
|
function ByteArrayClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var BA = function () {
|
|
ByteArray.call(this);
|
|
};
|
|
var BAp = BA.prototype = Object.create(ByteArray.prototype);
|
|
var c = new Class('ByteArray', BA, C(BA));
|
|
c.extendBuiltin(baseClass);
|
|
BAp.asGetNumericProperty = function (i) {
|
|
if (i >= this.length) {
|
|
return undefined;
|
|
}
|
|
return this.uint8v[i];
|
|
};
|
|
BAp.asSetNumericProperty = function (i, v) {
|
|
var len = i + 1;
|
|
this.ensureCapacity(len);
|
|
this.uint8v[i] = v;
|
|
if (len > this.length) {
|
|
this.length = len;
|
|
}
|
|
};
|
|
BAp.readUTF = function readUTF() {
|
|
return this.readUTFBytes(this.readShort());
|
|
};
|
|
BAp.readUTFBytes = function readUTFBytes(length) {
|
|
var pos = this.position;
|
|
if (pos + length > this.length) {
|
|
throwEOFError();
|
|
}
|
|
this.position += length;
|
|
return utf8encode(new Int8Array(this.a, pos, length));
|
|
};
|
|
BAp.writeUTF = function writeUTF(str) {
|
|
var bytes = utf8decode(str);
|
|
this.writeShort(bytes.length);
|
|
this.writeRawBytes(bytes);
|
|
};
|
|
BAp.writeUTFBytes = function writeUTFBytes(str) {
|
|
var bytes = utf8decode(str);
|
|
this.writeRawBytes(bytes);
|
|
};
|
|
BAp.toString = function toString() {
|
|
return utf8encode(new Int8Array(this.a, 0, this.length));
|
|
};
|
|
c.native = {
|
|
instance: {
|
|
length: {
|
|
get: function () {
|
|
return this.length;
|
|
},
|
|
set: function setLength(length) {
|
|
var cap = this.a.byteLength;
|
|
if (length > cap) {
|
|
this.ensureCapacity(length);
|
|
}
|
|
this.length = length;
|
|
this.position = clamp(this.position, 0, this.length);
|
|
}
|
|
},
|
|
bytesAvailable: {
|
|
get: function () {
|
|
return this.length - this.position;
|
|
}
|
|
},
|
|
position: {
|
|
get: function () {
|
|
return this.position;
|
|
},
|
|
set: function (p) {
|
|
this.position = p;
|
|
}
|
|
},
|
|
endian: {
|
|
get: function () {
|
|
return this.le ? 'littleEndian' : 'bigEndian';
|
|
},
|
|
set: function (e) {
|
|
this.le = e === 'littleEndian';
|
|
}
|
|
},
|
|
objectEncoding: {
|
|
get: function () {
|
|
return this.objectEncoding;
|
|
},
|
|
set: function (v) {
|
|
this.objectEncoding = v;
|
|
}
|
|
},
|
|
writeBytes: BAp.writeBytes,
|
|
writeBoolean: BAp.writeBoolean,
|
|
writeByte: BAp.writeByte,
|
|
writeShort: BAp.writeShort,
|
|
writeInt: BAp.writeInt,
|
|
writeUnsignedInt: BAp.writeUnsignedInt,
|
|
writeFloat: BAp.writeFloat,
|
|
writeDouble: BAp.writeDouble,
|
|
writeMultiByte: BAp.writeMultiByte,
|
|
writeObject: function writeObject(v) {
|
|
return AMFUtils.encodings[this.objectEncoding].write(this, v);
|
|
},
|
|
writeUTF: BAp.writeUTF,
|
|
writeUTFBytes: BAp.writeUTFBytes,
|
|
readBoolean: BAp.readBoolean,
|
|
readByte: BAp.readByte,
|
|
readBytes: BAp.readBytes,
|
|
readUnsignedByte: BAp.readUnsignedByte,
|
|
readShort: BAp.readShort,
|
|
readUnsignedShort: BAp.readUnsignedShort,
|
|
readInt: BAp.readInt,
|
|
readUnsignedInt: BAp.readUnsignedInt,
|
|
readFloat: BAp.readFloat,
|
|
readDouble: BAp.readDouble,
|
|
readMultiByte: BAp.readMultiByte,
|
|
readObject: function readObject() {
|
|
return AMFUtils.encodings[this.objectEncoding].read(this);
|
|
},
|
|
readUTF: BAp.readUTF,
|
|
readUTFBytes: BAp.readUTFBytes,
|
|
toString: BAp.toString,
|
|
clear: BAp.clear,
|
|
_compress: BAp.compress,
|
|
_uncompress: BAp.uncompress
|
|
},
|
|
static: {
|
|
defaultObjectEncoding: {
|
|
get: function () {
|
|
return ByteArray.DEFAULT_OBJECT_ENCODING;
|
|
},
|
|
set: function (e) {
|
|
ByteArray.DEFAULT_OBJECT_ENCODING = e;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
}
|
|
function DomainClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('File', instanceConstructor, C(instanceConstructor));
|
|
c.extend(baseClass);
|
|
c.native = {
|
|
instance: {
|
|
init: function (base) {
|
|
this.base = base;
|
|
this.nativeObject = new ApplicationDomain(AVM2.instance, base ? base.nativeObject : null);
|
|
},
|
|
loadBytes: function (byteArray, swfVersion) {
|
|
this.nativeObject.executeAbc(new AbcFile(byteArray.readRawBytes()));
|
|
},
|
|
getClass: function (className) {
|
|
return this.nativeObject.getClass(className);
|
|
}
|
|
},
|
|
static: {
|
|
currentDomain: {
|
|
get: function () {
|
|
var domain = Object.create(instanceConstructor.prototype);
|
|
domain.nativeObject = AVM2.currentDomain();
|
|
return domain;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
}
|
|
function SystemClass(runtime, scope, instanceConstructor, baseClass) {
|
|
var c = new Class('System', instanceConstructor, C(instanceConstructor));
|
|
c.extend(baseClass);
|
|
c.native = {
|
|
static: {
|
|
swfVersion: {
|
|
get: function () {
|
|
return 19;
|
|
}
|
|
},
|
|
apiVersion: {
|
|
get: function () {
|
|
return 26;
|
|
}
|
|
},
|
|
getArgv: function () {
|
|
return [];
|
|
},
|
|
getRunmode: function () {
|
|
return 'mixed';
|
|
}
|
|
}
|
|
};
|
|
return c;
|
|
}
|
|
function bugzilla(n) {
|
|
switch (n) {
|
|
case 574600:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return {
|
|
print: constant(print),
|
|
notImplemented: constant(notImplemented),
|
|
debugBreak: constant(debugBreak),
|
|
bugzilla: constant(bugzilla),
|
|
decodeURI: constant(decodeURI),
|
|
decodeURIComponent: constant(decodeURIComponent),
|
|
encodeURI: constant(encodeURI),
|
|
encodeURIComponent: constant(encodeURIComponent),
|
|
isNaN: constant(isNaN),
|
|
isFinite: constant(isFinite),
|
|
parseInt: constant(parseInt),
|
|
parseFloat: constant(parseFloat),
|
|
escape: constant(escape),
|
|
unescape: constant(unescape),
|
|
isXMLName: constant(typeof isXMLName !== 'undefined' ? isXMLName : function () {
|
|
notImplemented('Chrome doesn\'t support isXMLName.');
|
|
}),
|
|
Function: Function,
|
|
String: String,
|
|
Array: Array,
|
|
Number: Number,
|
|
Boolean: Boolean,
|
|
Math: Math,
|
|
Date: Date,
|
|
RegExp: RegExp,
|
|
Object: Object,
|
|
ObjectClass: ObjectClass,
|
|
Class: ClassClass,
|
|
NamespaceClass: NamespaceClass,
|
|
FunctionClass: FunctionClass,
|
|
MethodClosureClass: MethodClosureClass,
|
|
BooleanClass: BooleanClass,
|
|
StringClass: StringClass,
|
|
NumberClass: NumberClass,
|
|
intClass: intClass,
|
|
uintClass: uintClass,
|
|
ArrayClass: ArrayClass,
|
|
VectorClass: VectorClass,
|
|
ObjectVectorClass: ObjectVectorClass,
|
|
IntVectorClass: IntVectorClass,
|
|
UIntVectorClass: UIntVectorClass,
|
|
DoubleVectorClass: DoubleVectorClass,
|
|
ByteArrayClass: ByteArrayClass,
|
|
ProxyClass: ProxyClass,
|
|
ErrorClass: makeErrorClass('Error'),
|
|
DefinitionErrorClass: makeErrorClass('DefinitionError'),
|
|
EvalErrorClass: makeErrorClass('EvalError'),
|
|
RangeErrorClass: makeErrorClass('RangeError'),
|
|
ReferenceErrorClass: makeErrorClass('ReferenceError'),
|
|
SecurityErrorClass: makeErrorClass('SecurityError'),
|
|
SyntaxErrorClass: makeErrorClass('SyntaxError'),
|
|
TypeErrorClass: makeErrorClass('TypeError'),
|
|
URIErrorClass: makeErrorClass('URIError'),
|
|
VerifyErrorClass: makeErrorClass('VerifyError'),
|
|
UninitializedErrorClass: makeErrorClass('UninitializedError'),
|
|
ArgumentErrorClass: makeErrorClass('ArgumentError'),
|
|
DateClass: DateClass,
|
|
MathClass: MathClass,
|
|
RegExpClass: RegExpClass,
|
|
DictionaryClass: DictionaryClass,
|
|
XMLClass: XMLClass,
|
|
XMLListClass: XMLListClass,
|
|
QNameClass: QNameClass,
|
|
JSONClass: JSONClass,
|
|
ShumwayClass: ShumwayClass,
|
|
CapabilitiesClass: CapabilitiesClass,
|
|
FileClass: FileClass,
|
|
DomainClass: DomainClass,
|
|
SystemClass: SystemClass,
|
|
getQualifiedClassName: constant(function (value) {
|
|
if (value === null) {
|
|
return 'null';
|
|
} else if (value === undefined) {
|
|
return 'void';
|
|
}
|
|
switch (typeof value) {
|
|
case 'number':
|
|
if ((value | 0) === value) {
|
|
return 'int';
|
|
}
|
|
return 'Number';
|
|
case 'string':
|
|
return 'String';
|
|
case 'boolean':
|
|
return 'Boolean';
|
|
case 'object':
|
|
if (value instanceof Date) {
|
|
return 'Date';
|
|
}
|
|
var cls;
|
|
if (value instanceof Class) {
|
|
cls = value;
|
|
} else if (value.class) {
|
|
cls = value.class;
|
|
} else if (value.classInfo) {
|
|
cls = value;
|
|
}
|
|
if (cls) {
|
|
var name = cls.classInfo.instanceInfo.name;
|
|
var uri = name.namespaces[0].uri;
|
|
if (uri) {
|
|
return uri + '::' + name.name;
|
|
}
|
|
return name.name;
|
|
}
|
|
break;
|
|
}
|
|
return notImplemented(value + ' (' + typeof value + ')');
|
|
}),
|
|
getQualifiedSuperclassName: constant(function (value) {
|
|
switch (typeof value) {
|
|
case 'number':
|
|
case 'string':
|
|
case 'boolean':
|
|
return 'Object';
|
|
case 'function':
|
|
return 'Function';
|
|
case 'object':
|
|
if (value instanceof Date) {
|
|
return 'Object';
|
|
}
|
|
var cls;
|
|
if (value.class) {
|
|
cls = value.class;
|
|
} else if (value.classInfo) {
|
|
cls = value;
|
|
}
|
|
if (cls && cls.baseClass) {
|
|
var name = cls.baseClass.classInfo.instanceInfo.name;
|
|
var uri = name.namespaces[0].uri;
|
|
if (uri) {
|
|
return uri + '::' + name.name;
|
|
}
|
|
return name.name;
|
|
}
|
|
return 'Object';
|
|
}
|
|
return notImplemented(value + ' (superOf ' + typeof value + ')');
|
|
}),
|
|
getDefinitionByName: constant(function (name) {
|
|
var simpleName = String(name).replace('::', '.');
|
|
return AVM2.currentDomain().getClass(simpleName);
|
|
}),
|
|
describeTypeJSON: constant(describeTypeJSON),
|
|
original: jsGlobal[VM_NATIVE_BUILTIN_ORIGINALS]
|
|
};
|
|
function describeTypeJSON(o, flags) {
|
|
var Flags = {
|
|
HIDE_NSURI_METHODS: 1,
|
|
INCLUDE_BASES: 2,
|
|
INCLUDE_INTERFACES: 4,
|
|
INCLUDE_VARIABLES: 8,
|
|
INCLUDE_ACCESSORS: 16,
|
|
INCLUDE_METHODS: 32,
|
|
INCLUDE_METADATA: 64,
|
|
INCLUDE_CONSTRUCTOR: 128,
|
|
INCLUDE_TRAITS: 256,
|
|
USE_ITRAITS: 512,
|
|
HIDE_OBJECT: 1024
|
|
};
|
|
var declaredByKey = publicName('declaredBy');
|
|
var metadataKey = publicName('metadata');
|
|
var accessKey = publicName('access');
|
|
var uriKey = publicName('uri');
|
|
var nameKey = publicName('name');
|
|
var typeKey = publicName('type');
|
|
var returnTypeKey = publicName('returnType');
|
|
var valueKey = publicName('value');
|
|
var keyKey = publicName('key');
|
|
var parametersKey = publicName('parameters');
|
|
var optionalKey = publicName('optional');
|
|
var cls = o.classInfo ? o : Object.getPrototypeOf(o).class;
|
|
true;
|
|
var info = cls.classInfo;
|
|
var description = {};
|
|
description[nameKey] = unmangledQualifiedName(info.instanceInfo.name);
|
|
description[publicName('isDynamic')] = cls === o ? true : !(info.instanceInfo.flags & CONSTANT_ClassSealed);
|
|
description[publicName('isStatic')] = cls === o;
|
|
description[publicName('isFinal')] = cls === o ? true : !(info.instanceInfo.flags & CONSTANT_ClassFinal);
|
|
if (flags & Flags.INCLUDE_TRAITS) {
|
|
description[publicName('traits')] = addTraits(cls, flags);
|
|
}
|
|
var metadata = null;
|
|
if (info.metadata) {
|
|
metadata = Object.keys(info.metadata).map(function (key) {
|
|
return describeMetadata(info.metadata[key]);
|
|
});
|
|
}
|
|
description[metadataKey] = metadata;
|
|
return description;
|
|
function publicName(str) {
|
|
return Multiname.getPublicQualifiedName(str);
|
|
}
|
|
function unmangledQualifiedName(mn) {
|
|
var name = mn.name;
|
|
var namespace = mn.namespaces[0];
|
|
if (namespace && namespace.uri) {
|
|
return namespace.uri + '::' + name;
|
|
}
|
|
return name;
|
|
}
|
|
function describeMetadata(metadata) {
|
|
var result = {};
|
|
result[nameKey] = metadata.name;
|
|
result[valueKey] = metadata.value.map(function (value) {
|
|
var val = {};
|
|
val[keyKey] = value.key;
|
|
val[valueKey] = value.value;
|
|
return value;
|
|
});
|
|
return result;
|
|
}
|
|
function addTraits(cls, flags) {
|
|
var includedMembers = [
|
|
flags & Flags.INCLUDE_VARIABLES,
|
|
flags & Flags.INCLUDE_METHODS,
|
|
flags & Flags.INCLUDE_ACCESSORS,
|
|
flags & Flags.INCLUDE_ACCESSORS
|
|
];
|
|
var includeBases = flags & Flags.INCLUDE_BASES;
|
|
var includeMetadata = flags & Flags.INCLUDE_METADATA;
|
|
var obj = {};
|
|
var basesVal = obj[publicName('bases')] = includeBases ? [] : null;
|
|
if (flags & Flags.INCLUDE_INTERFACES) {
|
|
var interfacesVal = obj[publicName('interfaces')] = [];
|
|
if (flags & Flags.USE_ITRAITS) {
|
|
for (var key in cls.implementedInterfaces) {
|
|
var ifaceName = cls.implementedInterfaces[key].name;
|
|
interfacesVal.push(unmangledQualifiedName(ifaceName));
|
|
}
|
|
}
|
|
} else {
|
|
obj[publicName('interfaces')] = null;
|
|
}
|
|
var variablesVal = obj[publicName('variables')] = flags & Flags.INCLUDE_VARIABLES ? [] : null;
|
|
var accessorsVal = obj[publicName('accessors')] = flags & Flags.INCLUDE_ACCESSORS ? [] : null;
|
|
var methodsVal = obj[publicName('methods')] = flags & Flags.INCLUDE_METHODS ? [] : null;
|
|
var encounteredAccessors = {};
|
|
var addBase = false;
|
|
while (cls) {
|
|
var className = unmangledQualifiedName(cls.classInfo.instanceInfo.name);
|
|
if (includeBases && addBase) {
|
|
basesVal.push(className);
|
|
} else {
|
|
addBase = true;
|
|
}
|
|
if (flags & Flags.USE_ITRAITS) {
|
|
describeTraits(cls.classInfo.instanceInfo.traits);
|
|
} else {
|
|
describeTraits(cls.classInfo.traits);
|
|
}
|
|
cls = cls.baseClass;
|
|
}
|
|
function describeTraits(traits) {
|
|
true;
|
|
for (var i = 0; traits && i < traits.length; i++) {
|
|
var t = traits[i];
|
|
if (!includedMembers[t.kind] || !t.name.getNamespace().isPublic() && !t.name.uri) {
|
|
continue;
|
|
}
|
|
var name = unmangledQualifiedName(t.name);
|
|
if (encounteredAccessors[name]) {
|
|
var val = encounteredAccessors[name];
|
|
val[accessKey] = 'readwrite';
|
|
if (t.kind === TRAIT_Getter) {
|
|
val[typeKey] = unmangledQualifiedName(t.methodInfo.returnType);
|
|
}
|
|
continue;
|
|
}
|
|
var val = {};
|
|
if (includeMetadata && t.metadata) {
|
|
var metadataVal = val[metadataKey] = [];
|
|
for (var key in t.metadata) {
|
|
metadataVal.push(describeMetadata(t.metadata[key]));
|
|
}
|
|
} else {
|
|
val[metadataKey] = null;
|
|
}
|
|
val[declaredByKey] = className;
|
|
val[uriKey] = t.name.uri === undefined ? null : t.name.uri;
|
|
val[nameKey] = name;
|
|
if (!t.typeName && !(t.methodInfo && t.methodInfo.returnType)) {
|
|
continue;
|
|
}
|
|
val[t.kind === TRAIT_Method ? returnTypeKey : typeKey] = unmangledQualifiedName(t.kind === TRAIT_Slot ? t.typeName : t.methodInfo.returnType);
|
|
switch (t.kind) {
|
|
case TRAIT_Slot:
|
|
val[accessKey] = 'readwrite';
|
|
variablesVal.push(val);
|
|
break;
|
|
case TRAIT_Method:
|
|
var parametersVal = val[parametersKey] = [];
|
|
var parameters = t.methodInfo.parameters;
|
|
for (var j = 0; j < parameters.length; j++) {
|
|
var param = parameters[j];
|
|
var paramVal = {};
|
|
paramVal[typeKey] = param.type ? unmangledQualifiedName(param.type) : '*';
|
|
paramVal[optionalKey] = 'value' in param;
|
|
parametersVal.push(paramVal);
|
|
}
|
|
methodsVal.push(val);
|
|
break;
|
|
case TRAIT_Getter:
|
|
case TRAIT_Setter:
|
|
val[accessKey] = t.kind === TRAIT_Getter ? 'read' : 'write';
|
|
accessorsVal.push(val);
|
|
encounteredAccessors[name] = val;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
}
|
|
}();
|
|
function getNative(path) {
|
|
var chain = path.split('.');
|
|
var v = natives;
|
|
for (var i = 0, j = chain.length; i < j; i++) {
|
|
v = v && v[chain[i]];
|
|
}
|
|
true;
|
|
return v;
|
|
}
|
|
var disassemblerOptions = systemOptions.register(new OptionSet('Disassembler Options'));
|
|
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'));
|
|
function traceArray(writer, name, array, abc) {
|
|
if (array.length === 0) {
|
|
return;
|
|
}
|
|
writer.enter(name + ' {');
|
|
array.forEach(function (a, idx) {
|
|
a.trace(writer, abc);
|
|
});
|
|
writer.leave('}');
|
|
}
|
|
AbcFile.prototype.trace = function trace(writer) {
|
|
if (filter.value.indexOf('p') >= 0) {
|
|
this.constantPool.trace(writer);
|
|
}
|
|
if (filter.value.indexOf('N') >= 0) {
|
|
this.constantPool.traceMultinamesOnly(writer);
|
|
}
|
|
if (filter.value.indexOf('c') >= 0) {
|
|
traceArray(writer, 'classes', this.classes);
|
|
}
|
|
if (filter.value.indexOf('i') >= 0) {
|
|
traceArray(writer, 'instances', this.instances);
|
|
}
|
|
if (filter.value.indexOf('M') >= 0) {
|
|
traceArray(writer, 'metadata', this.metadata);
|
|
}
|
|
if (filter.value.indexOf('s') >= 0) {
|
|
traceArray(writer, 'scripts', this.scripts);
|
|
}
|
|
if (filter.value.indexOf('m') >= 0) {
|
|
traceArray(writer, 'methods', this.methods, this);
|
|
}
|
|
if (filter.value.indexOf('S') >= 0) {
|
|
traceSource(writer, this);
|
|
}
|
|
if (filter.value.indexOf('t') >= 0) {
|
|
traceStatistics(writer, this);
|
|
}
|
|
if (filter.value.indexOf('u') >= 0) {
|
|
print(JSON.stringify({
|
|
strings: this.constantPool.strings,
|
|
positionAfterUTFStrings: this.constantPool.positionAfterUTFStrings
|
|
}, null, 2));
|
|
}
|
|
};
|
|
ConstantPool.prototype.trace = function (writer) {
|
|
writer.enter('constantPool {');
|
|
for (var key in this) {
|
|
if (key === 'namespaces') {
|
|
writer.enter('namespaces {');
|
|
this.namespaces.forEach(function (ns, i) {
|
|
writer.writeLn(('' + i).padRight(' ', 3) + (ns ? ns.toString() : '*'));
|
|
});
|
|
writer.leave('}');
|
|
} else if (this[key] instanceof Array) {
|
|
writer.enter(key + ' ' + this[key].length + ' {');
|
|
writer.writeArray(this[key]);
|
|
writer.leave('}');
|
|
}
|
|
}
|
|
writer.leave('}');
|
|
};
|
|
ConstantPool.prototype.traceMultinamesOnly = function (writer) {
|
|
writer.writeArray(this.multinames, null, true);
|
|
};
|
|
ClassInfo.prototype.trace = function (writer) {
|
|
writer.enter('class ' + this + ' {');
|
|
traceArray(writer, 'traits', this.traits);
|
|
writer.leave('}');
|
|
};
|
|
MetaDataInfo.prototype.trace = function (writer) {
|
|
writer.enter(this + ' {');
|
|
this.value.forEach(function (item) {
|
|
writer.writeLn((item.key ? item.key + ': ' : '') + '"' + item.value + '"');
|
|
});
|
|
writer.leave('}');
|
|
};
|
|
InstanceInfo.prototype.trace = function (writer) {
|
|
writer.enter('instance ' + this + ' {');
|
|
traceArray(writer, 'traits', this.traits);
|
|
writer.leave('}');
|
|
};
|
|
ScriptInfo.prototype.trace = function (writer) {
|
|
writer.enter('script ' + this + ' {');
|
|
traceArray(writer, 'traits', this.traits);
|
|
writer.leave('}');
|
|
};
|
|
Trait.prototype.trace = function (writer) {
|
|
if (this.metadata) {
|
|
for (var key in this.metadata) {
|
|
if (this.metadata.hasOwnProperty(key)) {
|
|
this.metadata[key].trace(writer);
|
|
}
|
|
}
|
|
}
|
|
writer.writeLn(this);
|
|
};
|
|
function traceAbc(writer, abc) {
|
|
abc.trace(writer);
|
|
}
|
|
function traceOperand(operand, abc, code) {
|
|
var value = 0;
|
|
switch (operand.size) {
|
|
case 's08':
|
|
value = code.readS8();
|
|
break;
|
|
case 'u08':
|
|
value = code.readU8();
|
|
break;
|
|
case 's16':
|
|
value = code.readS16();
|
|
break;
|
|
case 's24':
|
|
value = code.readS24();
|
|
break;
|
|
case 'u30':
|
|
value = code.readU30();
|
|
break;
|
|
case 'u32':
|
|
value = code.readU32();
|
|
break;
|
|
default:
|
|
true;
|
|
break;
|
|
}
|
|
var description = '';
|
|
switch (operand.type) {
|
|
case '':
|
|
break;
|
|
case 'I':
|
|
description = abc.constantPool.ints[value];
|
|
break;
|
|
case 'U':
|
|
description = abc.constantPool.uints[value];
|
|
break;
|
|
case 'D':
|
|
description = abc.constantPool.doubles[value];
|
|
break;
|
|
case 'S':
|
|
description = abc.constantPool.strings[value];
|
|
break;
|
|
case 'N':
|
|
description = abc.constantPool.namespaces[value];
|
|
break;
|
|
case 'CI':
|
|
description = abc.classes[value];
|
|
break;
|
|
case 'M':
|
|
return abc.constantPool.multinames[value];
|
|
default:
|
|
description = '?';
|
|
break;
|
|
}
|
|
return operand.name + ':' + value + (description === '' ? '' : ' (' + description + ')');
|
|
}
|
|
function traceOperands(opcode, abc, code, rewind) {
|
|
rewind = rewind || false;
|
|
var old = code.position;
|
|
var str = '';
|
|
if (opcode.operands === null) {
|
|
str = 'null';
|
|
} else {
|
|
opcode.operands.forEach(function (op, i) {
|
|
str += traceOperand(op, abc, code);
|
|
if (i < opcode.operands.length - 1) {
|
|
str += ', ';
|
|
}
|
|
});
|
|
}
|
|
if (rewind) {
|
|
code.seek(old);
|
|
}
|
|
return str;
|
|
}
|
|
MethodInfo.prototype.trace = function trace(writer) {
|
|
var abc = this.abc;
|
|
writer.enter('method' + (this.name ? ' ' + this.name : '') + ' {');
|
|
writer.writeLn('flags: ' + getFlags(this.flags, 'NEED_ARGUMENTS|NEED_ACTIVATION|NEED_REST|HAS_OPTIONAL||NATIVE|SET_DXN|HAS_PARAM_NAMES'.split('|')));
|
|
writer.writeLn('parameters: ' + this.parameters.map(function (x) {
|
|
return (x.type ? Multiname.getQualifiedName(x.type) + '::' : '') + x.name;
|
|
}));
|
|
if (!this.code) {
|
|
writer.leave('}');
|
|
return;
|
|
}
|
|
var code = new AbcStream(this.code);
|
|
traceArray(writer, 'traits', this.traits);
|
|
writer.enter('code {');
|
|
while (code.remaining() > 0) {
|
|
var bc = code.readU8();
|
|
var opcode = opcodeTable[bc];
|
|
var str, defaultOffset, offset, count;
|
|
str = ('' + code.position).padRight(' ', 6);
|
|
switch (bc) {
|
|
case OP_lookupswitch:
|
|
str += opcode.name + ': defaultOffset: ' + code.readS24();
|
|
var caseCount = code.readU30();
|
|
str += ', caseCount: ' + caseCount;
|
|
for (var i = 0; i < caseCount + 1; i++) {
|
|
str += ' offset: ' + code.readS24();
|
|
}
|
|
writer.writeLn(str);
|
|
break;
|
|
default:
|
|
if (opcode) {
|
|
str += opcode.name.padRight(' ', 20);
|
|
if (!opcode.operands) {
|
|
true;
|
|
} else {
|
|
if (opcode.operands.length > 0) {
|
|
str += traceOperands(opcode, abc, code);
|
|
}
|
|
writer.writeLn(str);
|
|
}
|
|
} else {
|
|
true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
writer.leave('}');
|
|
writer.leave('}');
|
|
};
|
|
var SourceTracer = function () {
|
|
function literal(value) {
|
|
if (value === undefined) {
|
|
return 'undefined';
|
|
} else if (value === null) {
|
|
return 'null';
|
|
} else if (typeof value === 'string') {
|
|
return '"' + value + '"';
|
|
} else {
|
|
return String(value);
|
|
}
|
|
}
|
|
function getSignature(mi, excludeTypesAndDefaultValues) {
|
|
return mi.parameters.map(function (x) {
|
|
var str = x.name;
|
|
if (!excludeTypesAndDefaultValues) {
|
|
if (x.type) {
|
|
str += ':' + x.type.getName();
|
|
}
|
|
if (x.value !== undefined) {
|
|
str += ' = ' + literal(x.value);
|
|
}
|
|
}
|
|
return str;
|
|
}).join(', ');
|
|
}
|
|
function SourceTracer(writer) {
|
|
this.writer = writer;
|
|
}
|
|
SourceTracer.prototype = {
|
|
traceTraits: function traceTraits(traits, isStatic, inInterfaceNamespace) {
|
|
var writer = this.writer;
|
|
var tracer = this;
|
|
traits.forEach(function (trait) {
|
|
var str;
|
|
var accessModifier = Multiname.getAccessModifier(trait.name);
|
|
var namespaceName = trait.name.namespaces[0].uri;
|
|
if (namespaceName) {
|
|
if (namespaceName === 'http://adobe.com/AS3/2006/builtin') {
|
|
namespaceName = 'AS3';
|
|
}
|
|
if (accessModifier === 'public') {
|
|
str = inInterfaceNamespace === namespaceName ? '' : namespaceName;
|
|
} else {
|
|
str = accessModifier;
|
|
}
|
|
} else {
|
|
str = accessModifier;
|
|
}
|
|
if (isStatic) {
|
|
str += ' static';
|
|
}
|
|
if (trait.isSlot() || trait.isConst()) {
|
|
tracer.traceMetadata(trait.metadata);
|
|
if (trait.isConst()) {
|
|
str += ' const';
|
|
} else {
|
|
str += ' var';
|
|
}
|
|
str += ' ' + trait.name.getName();
|
|
if (trait.typeName) {
|
|
str += ':' + trait.typeName.getName();
|
|
}
|
|
if (trait.value) {
|
|
str += ' = ' + literal(trait.value);
|
|
}
|
|
writer.writeLn(str + ';');
|
|
} else if (trait.isMethod() || trait.isGetter() || trait.isSetter()) {
|
|
tracer.traceMetadata(trait.metadata);
|
|
var mi = trait.methodInfo;
|
|
if (trait.attributes & ATTR_Override) {
|
|
str += ' override';
|
|
}
|
|
if (mi.isNative()) {
|
|
str += ' native';
|
|
}
|
|
str += ' function';
|
|
str += trait.isGetter() ? ' get' : trait.isSetter() ? ' set' : '';
|
|
str += ' ' + trait.name.getName();
|
|
str += '(' + getSignature(mi) + ')';
|
|
str += mi.returnType ? ':' + mi.returnType.getName() : '';
|
|
if (true) {
|
|
var className;
|
|
var prefix = '';
|
|
if (trait.holder instanceof ClassInfo) {
|
|
className = trait.holder.instanceInfo.name;
|
|
if (className.namespaces[0].uri) {
|
|
prefix += className.namespaces[0].uri + '::';
|
|
}
|
|
prefix += className.getName();
|
|
prefix += '$/';
|
|
} else if (trait.holder instanceof InstanceInfo) {
|
|
className = trait.holder.name;
|
|
if (className.namespaces[0].uri) {
|
|
prefix += className.namespaces[0].uri + '::';
|
|
}
|
|
prefix += className.getName();
|
|
prefix += '/';
|
|
} else {
|
|
prefix = 'global/';
|
|
}
|
|
var getSet = trait.isGetter() ? 'get ' : trait.isSetter() ? 'set ' : '';
|
|
if (!mi.isNative()) {
|
|
}
|
|
}
|
|
if (mi.isNative()) {
|
|
writer.writeLn(str + ';');
|
|
} else {
|
|
if (inInterfaceNamespace) {
|
|
writer.writeLn(str + ';');
|
|
} else {
|
|
writer.writeLn(str + ' { notImplemented("' + trait.name.getName() + '"); }');
|
|
}
|
|
}
|
|
} else if (trait.isClass()) {
|
|
var className = trait.classInfo.instanceInfo.name;
|
|
writer.enter('package ' + className.namespaces[0].uri + ' {\n');
|
|
tracer.traceMetadata(trait.metadata);
|
|
tracer.traceClass(trait.classInfo);
|
|
writer.leave('\n}');
|
|
tracer.traceClassStub(trait);
|
|
} else {
|
|
notImplemented();
|
|
}
|
|
});
|
|
},
|
|
traceClassStub2: function traceClassStub(trait) {
|
|
var writer = this.writer;
|
|
var ci = trait.classInfo;
|
|
var ii = ci.instanceInfo;
|
|
var name = ii.name.getName();
|
|
var native = trait.metadata ? trait.metadata.native : null;
|
|
if (!native) {
|
|
return false;
|
|
}
|
|
writer.writeLn('Cut and paste the following into `native.js\' and edit accordingly');
|
|
writer.writeLn('8< --------------------------------------------------------------');
|
|
writer.enter('natives.' + native.cls + ' = function ' + native.cls + '(runtime, scope, instanceConstructor, baseClass) {');
|
|
writer.writeLn('var c = new Class("' + name + '", instanceConstructor, ApplicationDomain.passthroughCallable(instanceConstructor));');
|
|
writer.writeLn('c.extend(baseClass);\n');
|
|
function traceTraits(traits, isStatic) {
|
|
var nativeMethodTraits = [];
|
|
traits.forEach(function (trait, i) {
|
|
if (trait.isMethod() || trait.isGetter() || trait.isSetter()) {
|
|
if (trait.methodInfo.isNative()) {
|
|
nativeMethodTraits.push(trait);
|
|
}
|
|
}
|
|
});
|
|
nativeMethodTraits.forEach(function (trait, i) {
|
|
var mi = trait.methodInfo;
|
|
var traitName = trait.name.getName();
|
|
writer.writeLn('// ' + traitName + ' :: ' + (mi.parameters.length ? getSignature(mi) : 'void') + ' -> ' + (mi.returnType ? mi.returnType.getName() : 'any'));
|
|
var prop;
|
|
if (trait.isGetter()) {
|
|
prop = '"get ' + traitName + '"';
|
|
} else if (trait.isSetter()) {
|
|
prop = '"set ' + traitName + '"';
|
|
} else {
|
|
prop = traitName;
|
|
}
|
|
writer.enter(prop + ': function ' + traitName + '(' + getSignature(mi, true) + ') {');
|
|
writer.writeLn(' notImplemented("' + name + '.' + traitName + '");');
|
|
writer.leave('}' + (i === nativeMethodTraits.length - 1 ? '' : ',\n'));
|
|
});
|
|
}
|
|
writer.enter('c.nativeStatics = {');
|
|
traceTraits(ci.traits, true);
|
|
writer.leave('};\n');
|
|
writer.enter('c.nativeMethods = {');
|
|
traceTraits(ii.traits);
|
|
writer.leave('};\n');
|
|
writer.writeLn('return c;');
|
|
writer.leave('};');
|
|
writer.writeLn('-------------------------------------------------------------- >8');
|
|
return true;
|
|
},
|
|
traceClassStub: function traceClassStub(trait) {
|
|
var writer = this.writer;
|
|
var ci = trait.classInfo;
|
|
var ii = ci.instanceInfo;
|
|
var className = ii.name.getName();
|
|
var native = trait.metadata ? trait.metadata.native : null;
|
|
writer.writeLn('Cut and paste the following glue and edit accordingly.');
|
|
writer.writeLn('Class ' + ii);
|
|
writer.writeLn('8< --------------------------------------------------------------');
|
|
var uri = ii.name.namespaces[0].uri;
|
|
writer.enter('var ' + className + 'Definition = (function () {');
|
|
function maxTraitNameLength(traits) {
|
|
var length = 0;
|
|
traits.forEach(function (t) {
|
|
length = Math.max(t.name.name.length, length);
|
|
});
|
|
return length;
|
|
}
|
|
function quote(s) {
|
|
return '\'' + s + '\'';
|
|
}
|
|
function filterTraits(traits, isNative) {
|
|
function isMethod(x) {
|
|
return x.isMethod() || x.isGetter() || x.isSetter();
|
|
}
|
|
return {
|
|
properties: traits.filter(function (trait) {
|
|
return !isNative && !isMethod(trait);
|
|
}),
|
|
methods: traits.filter(function (trait) {
|
|
return isMethod(trait) && isNative === trait.methodInfo.isNative();
|
|
})
|
|
};
|
|
}
|
|
function writeTraits(traits, isNative, isStatic) {
|
|
traits = filterTraits(traits, isNative);
|
|
var methods = [];
|
|
var gettersAndSetters = createEmptyObject();
|
|
traits.methods.forEach(function (trait, i) {
|
|
var traitName = trait.name.getName();
|
|
if (trait.isGetter() || trait.isSetter()) {
|
|
if (!gettersAndSetters[traitName]) {
|
|
gettersAndSetters[traitName] = [];
|
|
}
|
|
gettersAndSetters[traitName].push(trait);
|
|
} else {
|
|
methods.push(trait);
|
|
}
|
|
});
|
|
function writeTrait(trait, writeComma) {
|
|
var mi = trait.methodInfo;
|
|
var traitName = trait.name.getName();
|
|
var signature = '// (' + (mi.parameters.length ? getSignature(mi) : 'void') + ') -> ' + (mi.returnType ? mi.returnType.getName() : 'any');
|
|
var propertyName = traitName;
|
|
if (trait.isGetter()) {
|
|
propertyName = 'get';
|
|
} else if (trait.isSetter()) {
|
|
propertyName = 'set';
|
|
}
|
|
writer.enter(propertyName + ': function ' + traitName + '(' + getSignature(mi, true) + ') { ' + signature);
|
|
writer.writeLn('notImplemented("' + className + '.' + traitName + '");');
|
|
if (!isStatic) {
|
|
if (trait.isGetter()) {
|
|
writer.writeLn('return this._' + traitName + ';');
|
|
} else if (trait.isSetter()) {
|
|
writer.writeLn('this._' + traitName + ' = ' + mi.parameters[0].name + ';');
|
|
}
|
|
}
|
|
writer.leave('}' + (writeComma ? ',' : ''));
|
|
}
|
|
for (var i = 0; i < methods.length; i++) {
|
|
writeTrait(methods[i], i < methods.length - 1);
|
|
}
|
|
var keyValues = toKeyValueArray(gettersAndSetters);
|
|
for (var j = 0; j < keyValues.length; j++) {
|
|
writer.enter(keyValues[j][0] + ': {');
|
|
var list = keyValues[j][1];
|
|
for (var i = 0; i < list.length; i++) {
|
|
writeTrait(list[i], i < list.length - 1);
|
|
}
|
|
writer.leave('}' + (j < keyValues.length - 1 ? ',' : ''));
|
|
}
|
|
traits.properties.forEach(function (trait, i) {
|
|
var traitName = trait.name.getName();
|
|
var last = i === traits.properties.length - 1;
|
|
if (trait.name.getNamespace().isPublic()) {
|
|
writer.writeLn(traitName + ': ' + quote('public ' + trait.name.name) + (last ? '' : ','));
|
|
}
|
|
});
|
|
}
|
|
writer.enter('return {');
|
|
writer.writeLn('// (' + getSignature(ii.init, false) + ')');
|
|
writer.writeLn('__class__: "' + uri + '.' + className + '",');
|
|
writer.enter('initialize: function () {');
|
|
writer.leave('},');
|
|
writer.enter('__glue__: {');
|
|
writer.enter('native: {');
|
|
writer.enter('static: {');
|
|
writeTraits(ci.traits, true, true);
|
|
writer.leave('},');
|
|
writer.enter('instance: {');
|
|
writeTraits(ii.traits, true);
|
|
writer.leave('}');
|
|
writer.leave('},');
|
|
writer.enter('script: {');
|
|
writer.writeLn('instance: Glue.ALL');
|
|
writer.leave('}');
|
|
writer.leave('}');
|
|
writer.leave('};');
|
|
writer.leave('}).call(this);');
|
|
writer.writeLn('-------------------------------------------------------------- >8');
|
|
return true;
|
|
},
|
|
traceClass: function traceClass(ci) {
|
|
var writer = this.writer;
|
|
var ii = ci.instanceInfo;
|
|
var name = ii.name;
|
|
var str = Multiname.getAccessModifier(name);
|
|
if (ii.isFinal()) {
|
|
str += ' final';
|
|
}
|
|
if (!ii.isSealed()) {
|
|
str += ' dynamic';
|
|
}
|
|
str += ii.isInterface() ? ' interface ' : ' class ';
|
|
str += name.getName();
|
|
if (ii.superName && ii.superName.getName() !== 'Object') {
|
|
str += ' extends ' + ii.superName.getName();
|
|
}
|
|
if (ii.interfaces.length) {
|
|
str += ' implements ' + ii.interfaces.map(function (x) {
|
|
return x.getName();
|
|
}).join(', ');
|
|
}
|
|
writer.enter(str + ' {');
|
|
if (!ii.isInterface()) {
|
|
writer.writeLn('public function ' + name.getName() + '(' + getSignature(ii.init) + ') {}');
|
|
}
|
|
var interfaceNamespace;
|
|
if (ii.isInterface()) {
|
|
interfaceNamespace = name.namespaces[0].uri + ':' + name.name;
|
|
}
|
|
this.traceTraits(ci.traits, true, interfaceNamespace);
|
|
this.traceTraits(ii.traits, false, interfaceNamespace);
|
|
writer.leave('}');
|
|
},
|
|
traceMetadata: function traceMetadata(metadata) {
|
|
var writer = this.writer;
|
|
for (var key in metadata) {
|
|
if (metadata.hasOwnProperty(key)) {
|
|
if (key.indexOf('__') === 0) {
|
|
continue;
|
|
}
|
|
writer.writeLn('[' + key + '(' + metadata[key].value.map(function (m) {
|
|
var str = m.key ? m.key + '=' : '';
|
|
return str + '"' + m.value + '"';
|
|
}).join(', ') + ')]');
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return SourceTracer;
|
|
}();
|
|
function traceSource(writer, abc) {
|
|
var tracer = new SourceTracer(writer);
|
|
abc.scripts.forEach(function (script) {
|
|
tracer.traceTraits(script.traits);
|
|
});
|
|
}
|
|
function traceStatistics(writer, abc) {
|
|
var libraryClassCounter = new Shumway.Metrics.Counter(true);
|
|
var librarySuperClassCounter = new Shumway.Metrics.Counter(true);
|
|
var libraryMethodCounter = new Shumway.Metrics.Counter(true);
|
|
var libraryProperties = new Shumway.Metrics.Counter(true);
|
|
var definedClasses = {};
|
|
var definedMethods = {};
|
|
var definedProperties = {};
|
|
abc.classes.forEach(function (x) {
|
|
var className = x.instanceInfo.name.name;
|
|
definedClasses[className] = true;
|
|
});
|
|
abc.scripts.forEach(function (s) {
|
|
s.traits.forEach(function (t) {
|
|
if (t.isClass()) {
|
|
var superClassName = t.classInfo.instanceInfo.superName ? t.classInfo.instanceInfo.superName.name : '?';
|
|
if (!(superClassName in definedClasses)) {
|
|
librarySuperClassCounter.count(superClassName);
|
|
}
|
|
t.classInfo.traits.forEach(function (st) {
|
|
if (st.isMethod()) {
|
|
definedMethods[st.name.name] = true;
|
|
} else {
|
|
definedProperties[st.name.name] = true;
|
|
}
|
|
});
|
|
t.classInfo.instanceInfo.traits.forEach(function (it) {
|
|
if (it.isMethod() && !(it.attributes & ATTR_Override)) {
|
|
definedMethods[it.name.name] = true;
|
|
} else {
|
|
definedProperties[it.name.name] = true;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
var opCounter = new Shumway.Metrics.Counter(true);
|
|
abc.methods.forEach(function (m) {
|
|
if (!m.code) {
|
|
return;
|
|
}
|
|
function readOperand(operand) {
|
|
var value = 0;
|
|
switch (operand.size) {
|
|
case 's08':
|
|
value = code.readS8();
|
|
break;
|
|
case 'u08':
|
|
value = code.readU8();
|
|
break;
|
|
case 's16':
|
|
value = code.readS16();
|
|
break;
|
|
case 's24':
|
|
value = code.readS24();
|
|
break;
|
|
case 'u30':
|
|
value = code.readU30();
|
|
break;
|
|
case 'u32':
|
|
value = code.readU32();
|
|
break;
|
|
default:
|
|
true;
|
|
break;
|
|
}
|
|
var description = '';
|
|
switch (operand.type) {
|
|
case '':
|
|
break;
|
|
case 'I':
|
|
description = abc.constantPool.ints[value];
|
|
break;
|
|
case 'U':
|
|
description = abc.constantPool.uints[value];
|
|
break;
|
|
case 'D':
|
|
description = abc.constantPool.doubles[value];
|
|
break;
|
|
case 'S':
|
|
description = abc.constantPool.strings[value];
|
|
break;
|
|
case 'N':
|
|
description = abc.constantPool.namespaces[value];
|
|
break;
|
|
case 'CI':
|
|
description = abc.classes[value];
|
|
break;
|
|
case 'M':
|
|
description = abc.constantPool.multinames[value];
|
|
break;
|
|
default:
|
|
description = '?';
|
|
break;
|
|
}
|
|
return description;
|
|
}
|
|
var code = new AbcStream(m.code);
|
|
while (code.remaining() > 0) {
|
|
var bc = code.readU8();
|
|
var op = opcodeTable[bc];
|
|
var operands = null;
|
|
if (op) {
|
|
opCounter.count(op.name);
|
|
if (op.operands) {
|
|
operands = op.operands.map(readOperand);
|
|
}
|
|
switch (bc) {
|
|
case OP_call:
|
|
case OP_callmethod:
|
|
continue;
|
|
case OP_callproperty:
|
|
case OP_callproplex:
|
|
case OP_callpropvoid:
|
|
case OP_callstatic:
|
|
case OP_callsuper:
|
|
case OP_callsupervoid:
|
|
if (operands[0] && !(operands[0].name in definedMethods)) {
|
|
libraryMethodCounter.count(operands[0].name);
|
|
}
|
|
break;
|
|
case OP_constructprop:
|
|
if (operands[0] && !(operands[0].name in definedClasses)) {
|
|
libraryClassCounter.count(operands[0].name);
|
|
}
|
|
break;
|
|
case OP_getproperty:
|
|
case OP_setproperty:
|
|
if (operands[0] && !(operands[0].name in definedProperties)) {
|
|
libraryProperties.count(operands[0].name);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
writer.writeLn(JSON.stringify({
|
|
definedClasses: definedClasses,
|
|
definedMethods: definedMethods,
|
|
definedProperties: definedProperties,
|
|
libraryClasses: libraryClassCounter.counts,
|
|
librarySuperClasses: librarySuperClassCounter.counts,
|
|
libraryMethods: libraryMethodCounter.counts,
|
|
libraryProperties: libraryProperties.counts,
|
|
operations: opCounter.counts
|
|
}, null, 2));
|
|
}
|
|
var Shumway;
|
|
(function (Shumway) {
|
|
(function (AVM2) {
|
|
var OP = Shumway.AVM2.ABC.OP;
|
|
var Scope = Shumway.AVM2.Runtime.Scope;
|
|
var asCoerceByMultiname = Shumway.AVM2.Runtime.asCoerceByMultiname;
|
|
var asGetSlot = Shumway.AVM2.Runtime.asGetSlot;
|
|
var asSetSlot = Shumway.AVM2.Runtime.asSetSlot;
|
|
var asHasNext2 = Shumway.AVM2.Runtime.asHasNext2;
|
|
var asCoerce = Shumway.AVM2.Runtime.asCoerce;
|
|
var asCoerceString = Shumway.AVM2.Runtime.asCoerceString;
|
|
var asAsType = Shumway.AVM2.Runtime.asAsType;
|
|
var asTypeOf = Shumway.AVM2.Runtime.asTypeOf;
|
|
var asIsInstanceOf = Shumway.AVM2.Runtime.asIsInstanceOf;
|
|
var asIsType = Shumway.AVM2.Runtime.asIsType;
|
|
var applyType = Shumway.AVM2.Runtime.applyType;
|
|
var createFunction = Shumway.AVM2.Runtime.createFunction;
|
|
var createClass = Shumway.AVM2.Runtime.createClass;
|
|
var getDescendants = Shumway.AVM2.Runtime.getDescendants;
|
|
var checkFilter = Shumway.AVM2.Runtime.checkFilter;
|
|
var asAdd = Shumway.AVM2.Runtime.asAdd;
|
|
var translateError = Shumway.AVM2.Runtime.translateError;
|
|
var asCreateActivation = Shumway.AVM2.Runtime.asCreateActivation;
|
|
var sliceArguments = Shumway.AVM2.Runtime.sliceArguments;
|
|
var boxValue = Shumway.ObjectUtilities.boxValue;
|
|
var popManyInto = Shumway.ArrayUtilities.popManyInto;
|
|
var construct = Shumway.AVM2.Runtime.construct;
|
|
var Multiname = Shumway.AVM2.ABC.Multiname;
|
|
var ScopeStack = function () {
|
|
function ScopeStack(parent) {
|
|
this.parent = parent;
|
|
this.stack = [];
|
|
this.isWith = [];
|
|
}
|
|
ScopeStack.prototype.push = function (object, isWith) {
|
|
this.stack.push(object);
|
|
this.isWith.push(!(!isWith));
|
|
};
|
|
ScopeStack.prototype.get = function (index) {
|
|
return this.stack[index];
|
|
};
|
|
ScopeStack.prototype.clear = function () {
|
|
this.stack.length = 0;
|
|
this.isWith.length = 0;
|
|
};
|
|
ScopeStack.prototype.pop = function () {
|
|
this.isWith.pop();
|
|
this.stack.pop();
|
|
};
|
|
ScopeStack.prototype.topScope = function () {
|
|
if (!this.scopes) {
|
|
this.scopes = [];
|
|
}
|
|
var parent = this.parent;
|
|
for (var i = 0; i < this.stack.length; i++) {
|
|
var object = this.stack[i], isWith = this.isWith[i], scope = this.scopes[i];
|
|
if (!scope || scope.parent !== parent || scope.object !== object || scope.isWith !== isWith) {
|
|
scope = this.scopes[i] = new Scope(parent, object, isWith);
|
|
}
|
|
parent = scope;
|
|
}
|
|
return parent;
|
|
};
|
|
return ScopeStack;
|
|
}();
|
|
function popNameInto(stack, mn, out) {
|
|
out.flags = mn.flags;
|
|
if (mn.isRuntimeName()) {
|
|
out.name = stack.pop();
|
|
} else {
|
|
out.name = mn.name;
|
|
}
|
|
if (mn.isRuntimeNamespace()) {
|
|
out.namespaces = [
|
|
stack.pop()
|
|
];
|
|
} else {
|
|
out.namespaces = mn.namespaces;
|
|
}
|
|
}
|
|
var Interpreter = function () {
|
|
function Interpreter() {
|
|
}
|
|
Interpreter.interpretMethod = function ($this, method, savedScope, methodArgs) {
|
|
true;
|
|
Counter.count('Interpret Method');
|
|
var abc = method.abc;
|
|
var ints = abc.constantPool.ints;
|
|
var uints = abc.constantPool.uints;
|
|
var doubles = abc.constantPool.doubles;
|
|
var strings = abc.constantPool.strings;
|
|
var methods = abc.methods;
|
|
var multinames = abc.constantPool.multinames;
|
|
var domain = abc.applicationDomain;
|
|
var exceptions = method.exceptions;
|
|
var locals = [
|
|
$this
|
|
];
|
|
var stack = [], scopeStack = new ScopeStack(savedScope);
|
|
var parameterCount = method.parameters.length;
|
|
var argCount = methodArgs.length;
|
|
var value;
|
|
for (var i = 0; i < parameterCount; i++) {
|
|
var parameter = method.parameters[i];
|
|
if (i < argCount) {
|
|
value = methodArgs[i];
|
|
} else {
|
|
value = parameter.value;
|
|
}
|
|
if (parameter.type && !parameter.type.isAnyName()) {
|
|
value = asCoerceByMultiname(domain, parameter.type, value);
|
|
}
|
|
locals.push(value);
|
|
}
|
|
if (method.needsRest()) {
|
|
locals.push(sliceArguments(methodArgs, parameterCount));
|
|
} else if (method.needsArguments()) {
|
|
locals.push(sliceArguments(methodArgs, 0));
|
|
}
|
|
var bytecodes = method.analysis.bytecodes;
|
|
var object, index, multiname, result, a, b, args = [], mn = Multiname.TEMPORARY;
|
|
interpretLabel:
|
|
for (var pc = 0, end = bytecodes.length; pc < end;) {
|
|
try {
|
|
var bc = bytecodes[pc];
|
|
var op = bc.op;
|
|
switch (op | 0) {
|
|
case 3:
|
|
throw stack.pop();
|
|
case 4:
|
|
popNameInto(stack, multinames[bc.index], mn);
|
|
stack.push(stack.pop().asGetSuper(savedScope, mn.namespaces, mn.name, mn.flags));
|
|
break;
|
|
case 5:
|
|
value = stack.pop();
|
|
popNameInto(stack, multinames[bc.index], mn);
|
|
stack.pop().asSetSuper(savedScope, mn.namespaces, mn.name, mn.flags, value);
|
|
break;
|
|
case 8:
|
|
locals[bc.index] = undefined;
|
|
break;
|
|
case 12:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = !(a < b) ? bc.offset : pc + 1;
|
|
continue;
|
|
case 24:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = a >= b ? bc.offset : pc + 1;
|
|
continue;
|
|
case 13:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = !(a <= b) ? bc.offset : pc + 1;
|
|
continue;
|
|
case 23:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = a > b ? bc.offset : pc + 1;
|
|
continue;
|
|
case 14:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = !(a > b) ? bc.offset : pc + 1;
|
|
continue;
|
|
case 22:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = a <= b ? bc.offset : pc + 1;
|
|
continue;
|
|
case 15:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = !(a >= b) ? bc.offset : pc + 1;
|
|
continue;
|
|
case 21:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = a < b ? bc.offset : pc + 1;
|
|
continue;
|
|
case 16:
|
|
pc = bc.offset;
|
|
continue;
|
|
case 17:
|
|
pc = !(!stack.pop()) ? bc.offset : pc + 1;
|
|
continue;
|
|
case 18:
|
|
pc = !stack.pop() ? bc.offset : pc + 1;
|
|
continue;
|
|
case 19:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = a == b ? bc.offset : pc + 1;
|
|
continue;
|
|
case 20:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = a != b ? bc.offset : pc + 1;
|
|
continue;
|
|
case 25:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = a === b ? bc.offset : pc + 1;
|
|
continue;
|
|
case 26:
|
|
b = stack.pop();
|
|
a = stack.pop();
|
|
pc = a !== b ? bc.offset : pc + 1;
|
|
continue;
|
|
case 27:
|
|
index = stack.pop();
|
|
if (index < 0 || index >= bc.offsets.length) {
|
|
index = bc.offsets.length - 1;
|
|
}
|
|
pc = bc.offsets[index];
|
|
continue;
|
|
case 28:
|
|
scopeStack.push(boxValue(stack.pop()), true);
|
|
break;
|
|
case 29:
|
|
scopeStack.pop();
|
|
break;
|
|
case 30:
|
|
index = stack.pop();
|
|
stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asNextName(index);
|
|
break;
|
|
case 35:
|
|
index = stack.pop();
|
|
stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asNextValue(index);
|
|
break;
|
|
case 50:
|
|
result = asHasNext2(locals[bc.object], locals[bc.index]);
|
|
locals[bc.object] = result.object;
|
|
locals[bc.index] = result.index;
|
|
stack.push(!(!result.index));
|
|
break;
|
|
case 32:
|
|
stack.push(null);
|
|
break;
|
|
case 33:
|
|
stack.push(undefined);
|
|
break;
|
|
case 36:
|
|
case 37:
|
|
stack.push(bc.value);
|
|
break;
|
|
case 44:
|
|
stack.push(strings[bc.index]);
|
|
break;
|
|
case 45:
|
|
stack.push(ints[bc.index]);
|
|
break;
|
|
case 46:
|
|
stack.push(uints[bc.index]);
|
|
break;
|
|
case 47:
|
|
stack.push(doubles[bc.index]);
|
|
break;
|
|
case 38:
|
|
stack.push(true);
|
|
break;
|
|
case 39:
|
|
stack.push(false);
|
|
break;
|
|
case 40:
|
|
stack.push(NaN);
|
|
break;
|
|
case 41:
|
|
stack.pop();
|
|
break;
|
|
case 42:
|
|
stack.push(stack[stack.length - 1]);
|
|
break;
|
|
case 43:
|
|
object = stack[stack.length - 1];
|
|
stack[stack.length - 1] = stack[stack.length - 2];
|
|
stack[stack.length - 2] = object;
|
|
break;
|
|
case 48:
|
|
scopeStack.push(boxValue(stack.pop()), false);
|
|
break;
|
|
case 64:
|
|
stack.push(createFunction(methods[bc.index], scopeStack.topScope(), true));
|
|
break;
|
|
case 65:
|
|
popManyInto(stack, bc.argCount, args);
|
|
object = stack.pop();
|
|
stack[stack.length - 1] = stack[stack.length - 1].apply(object, args);
|
|
break;
|
|
case 66:
|
|
popManyInto(stack, bc.argCount, args);
|
|
stack[stack.length - 1] = construct(stack[stack.length - 1], args);
|
|
break;
|
|
case 71:
|
|
return;
|
|
case 72:
|
|
if (method.returnType) {
|
|
return asCoerceByMultiname(domain, method.returnType, stack.pop());
|
|
}
|
|
return stack.pop();
|
|
case 73:
|
|
popManyInto(stack, bc.argCount, args);
|
|
object = stack.pop();
|
|
savedScope.object.baseClass.instanceConstructorNoInitialize.apply(object, args);
|
|
break;
|
|
case 74:
|
|
popManyInto(stack, bc.argCount, args);
|
|
popNameInto(stack, multinames[bc.index], mn);
|
|
object = boxValue(stack[stack.length - 1]);
|
|
object = object.asConstructProperty(mn.namespaces, mn.name, mn.flags, args);
|
|
stack[stack.length - 1] = object;
|
|
break;
|
|
case 75:
|
|
Shumway.Debug.notImplemented('OP.callsuperid');
|
|
break;
|
|
case 76:
|
|
case 70:
|
|
case 79:
|
|
popManyInto(stack, bc.argCount, args);
|
|
popNameInto(stack, multinames[bc.index], mn);
|
|
result = boxValue(stack.pop()).asCallProperty(mn.namespaces, mn.name, mn.flags, op === 76, args);
|
|
if (op !== 79) {
|
|
stack.push(result);
|
|
}
|
|
break;
|
|
case 69:
|
|
case 78:
|
|
popManyInto(stack, bc.argCount, args);
|
|
popNameInto(stack, multinames[bc.index], mn);
|
|
result = stack.pop().asCallSuper(savedScope, mn.namespaces, mn.name, mn.flags, args);
|
|
if (op !== 78) {
|
|
stack.push(result);
|
|
}
|
|
break;
|
|
case 83:
|
|
popManyInto(stack, bc.argCount, args);
|
|
stack[stack.length - 1] = applyType(domain, stack[stack.length - 1], args);
|
|
break;
|
|
case 85:
|
|
object = {};
|
|
for (var i = 0; i < bc.argCount; i++) {
|
|
value = stack.pop();
|
|
object[Multiname.getPublicQualifiedName(stack.pop())] = value;
|
|
}
|
|
stack.push(object);
|
|
break;
|
|
case 86:
|
|
object = [];
|
|
popManyInto(stack, bc.argCount, args);
|
|
object.push.apply(object, args);
|
|
stack.push(object);
|
|
break;
|
|
case 87:
|
|
true;
|
|
stack.push(asCreateActivation(method));
|
|
break;
|
|
case 88:
|
|
stack[stack.length - 1] = createClass(abc.classes[bc.index], stack[stack.length - 1], scopeStack.topScope());
|
|
break;
|
|
case 89:
|
|
popNameInto(stack, multinames[bc.index], mn);
|
|
stack.push(getDescendants(stack.pop(), mn));
|
|
break;
|
|
case 90:
|
|
true;
|
|
stack.push(exceptions[bc.index].scopeObject);
|
|
break;
|
|
case 94:
|
|
case 93:
|
|
popNameInto(stack, multinames[bc.index], mn);
|
|
stack.push(scopeStack.topScope().findScopeProperty(mn.namespaces, mn.name, mn.flags, domain, op === 93, false));
|
|
break;
|
|
case 96:
|
|
multiname = multinames[bc.index];
|
|
object = scopeStack.topScope().findScopeProperty(multiname.namespaces, multiname.name, multiname.flags, domain, true, false);
|
|
stack.push(object.asGetProperty(multiname.namespaces, multiname.name, multiname.flags));
|
|
break;
|
|
case 104:
|
|
case 97:
|
|
value = stack.pop();
|
|
popNameInto(stack, multinames[bc.index], mn);
|
|
boxValue(stack.pop()).asSetProperty(mn.namespaces, mn.name, mn.flags, value);
|
|
break;
|
|
case 98:
|
|
stack.push(locals[bc.index]);
|
|
break;
|
|
case 99:
|
|
locals[bc.index] = stack.pop();
|
|
break;
|
|
case 100:
|
|
stack.push(savedScope.global.object);
|
|
break;
|
|
case 101:
|
|
stack.push(scopeStack.get(bc.index));
|
|
break;
|
|
case 102:
|
|
popNameInto(stack, multinames[bc.index], mn);
|
|
stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asGetProperty(mn.namespaces, mn.name, mn.flags);
|
|
break;
|
|
case 106:
|
|
popNameInto(stack, multinames[bc.index], mn);
|
|
stack[stack.length - 1] = boxValue(stack[stack.length - 1]).asDeleteProperty(mn.namespaces, mn.name, mn.flags);
|
|
break;
|
|
case 108:
|
|
stack[stack.length - 1] = asGetSlot(stack[stack.length - 1], bc.index);
|
|
break;
|
|
case 109:
|
|
value = stack.pop();
|
|
object = stack.pop();
|
|
asSetSlot(object, bc.index, value);
|
|
break;
|
|
case 112:
|
|
stack[stack.length - 1] = stack[stack.length - 1] + '';
|
|
break;
|
|
case 131:
|
|
case 115:
|
|
stack[stack.length - 1] |= 0;
|
|
break;
|
|
case 136:
|
|
case 116:
|
|
stack[stack.length - 1] >>>= 0;
|
|
break;
|
|
case 132:
|
|
case 117:
|
|
stack[stack.length - 1] = +stack[stack.length - 1];
|
|
break;
|
|
case 129:
|
|
case 118:
|
|
stack[stack.length - 1] = !(!stack[stack.length - 1]);
|
|
break;
|
|
case 120:
|
|
stack[stack.length - 1] = checkFilter(stack[stack.length - 1]);
|
|
break;
|
|
case 128:
|
|
stack[stack.length - 1] = asCoerce(domain.getType(multinames[bc.index]), stack[stack.length - 1]);
|
|
break;
|
|
case 130:
|
|
break;
|
|
case 133:
|
|
stack[stack.length - 1] = asCoerceString(stack[stack.length - 1]);
|
|
break;
|
|
case 135:
|
|
stack[stack.length - 2] = asAsType(stack.pop(), stack[stack.length - 1]);
|
|
break;
|
|
case 137:
|
|
object = stack[stack.length - 1];
|
|
stack[stack.length - 1] = object == undefined ? null : object;
|
|
break;
|
|
case 144:
|
|
stack[stack.length - 1] = -stack[stack.length - 1];
|
|
break;
|
|
case 145:
|
|
++stack[stack.length - 1];
|
|
break;
|
|
case 146:
|
|
++locals[bc.index];
|
|
break;
|
|
case 147:
|
|
--stack[stack.length - 1];
|
|
break;
|
|
case 148:
|
|
--locals[bc.index];
|
|
break;
|
|
case 149:
|
|
stack[stack.length - 1] = asTypeOf(stack[stack.length - 1]);
|
|
break;
|
|
case 150:
|
|
stack[stack.length - 1] = !stack[stack.length - 1];
|
|
break;
|
|
case 151:
|
|
stack[stack.length - 1] = ~stack[stack.length - 1];
|
|
break;
|
|
case 160:
|
|
stack[stack.length - 2] = asAdd(stack[stack.length - 2], stack.pop());
|
|
break;
|
|
case 161:
|
|
stack[stack.length - 2] -= stack.pop();
|
|
break;
|
|
case 162:
|
|
stack[stack.length - 2] *= stack.pop();
|
|
break;
|
|
case 163:
|
|
stack[stack.length - 2] /= stack.pop();
|
|
break;
|
|
case 164:
|
|
stack[stack.length - 2] %= stack.pop();
|
|
break;
|
|
case 165:
|
|
stack[stack.length - 2] <<= stack.pop();
|
|
break;
|
|
case 166:
|
|
stack[stack.length - 2] >>= stack.pop();
|
|
break;
|
|
case 167:
|
|
stack[stack.length - 2] >>>= stack.pop();
|
|
break;
|
|
case 168:
|
|
stack[stack.length - 2] &= stack.pop();
|
|
break;
|
|
case 169:
|
|
stack[stack.length - 2] |= stack.pop();
|
|
break;
|
|
case 170:
|
|
stack[stack.length - 2] ^= stack.pop();
|
|
break;
|
|
case 171:
|
|
stack[stack.length - 2] = stack[stack.length - 2] == stack.pop();
|
|
break;
|
|
case 172:
|
|
stack[stack.length - 2] = stack[stack.length - 2] === stack.pop();
|
|
break;
|
|
case 173:
|
|
stack[stack.length - 2] = stack[stack.length - 2] < stack.pop();
|
|
break;
|
|
case 174:
|
|
stack[stack.length - 2] = stack[stack.length - 2] <= stack.pop();
|
|
break;
|
|
case 175:
|
|
stack[stack.length - 2] = stack[stack.length - 2] > stack.pop();
|
|
break;
|
|
case 176:
|
|
stack[stack.length - 2] = stack[stack.length - 2] >= stack.pop();
|
|
break;
|
|
case 177:
|
|
stack[stack.length - 2] = asIsInstanceOf(stack.pop(), stack[stack.length - 1]);
|
|
break;
|
|
case 178:
|
|
stack[stack.length - 1] = asIsType(domain.getType(multinames[bc.index]), stack[stack.length - 1]);
|
|
break;
|
|
case 179:
|
|
stack[stack.length - 2] = asIsType(stack.pop(), stack[stack.length - 1]);
|
|
break;
|
|
case 180:
|
|
stack[stack.length - 2] = boxValue(stack.pop()).asHasProperty(null, stack[stack.length - 1]);
|
|
break;
|
|
case 192:
|
|
stack[stack.length - 1] = (stack[stack.length - 1] | 0) + 1;
|
|
break;
|
|
case 193:
|
|
stack[stack.length - 1] = (stack[stack.length - 1] | 0) - 1;
|
|
break;
|
|
case 194:
|
|
locals[bc.index] = (locals[bc.index] | 0) + 1;
|
|
break;
|
|
case 195:
|
|
locals[bc.index] = (locals[bc.index] | 0) - 1;
|
|
break;
|
|
case 196:
|
|
stack[stack.length - 1] = ~stack[stack.length - 1];
|
|
break;
|
|
case 197:
|
|
stack[stack.length - 2] = stack[stack.length - 2] + stack.pop() | 0;
|
|
break;
|
|
case 198:
|
|
stack[stack.length - 2] = stack[stack.length - 2] - stack.pop() | 0;
|
|
break;
|
|
case 199:
|
|
stack[stack.length - 2] = stack[stack.length - 2] * stack.pop() | 0;
|
|
break;
|
|
case 208:
|
|
case 209:
|
|
case 210:
|
|
case 211:
|
|
stack.push(locals[op - 208]);
|
|
break;
|
|
case 212:
|
|
case 213:
|
|
case 214:
|
|
case 215:
|
|
locals[op - 212] = stack.pop();
|
|
break;
|
|
case 239:
|
|
case 240:
|
|
case 241:
|
|
break;
|
|
default:
|
|
Shumway.Debug.notImplemented(Shumway.AVM2.opcodeName(op));
|
|
}
|
|
pc++;
|
|
} catch (e) {
|
|
if (exceptions.length < 1) {
|
|
throw e;
|
|
}
|
|
e = translateError(domain, e);
|
|
for (var i = 0, j = exceptions.length; i < j; i++) {
|
|
var handler = exceptions[i];
|
|
if (pc >= handler.start && pc <= handler.end && (!handler.typeName || domain.getType(handler.typeName).isInstance(e))) {
|
|
stack.length = 0;
|
|
stack.push(e);
|
|
scopeStack.clear();
|
|
pc = handler.offset;
|
|
continue interpretLabel;
|
|
}
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
};
|
|
return Interpreter;
|
|
}();
|
|
AVM2.Interpreter = Interpreter;
|
|
}(Shumway.AVM2 || (Shumway.AVM2 = {})));
|
|
var AVM2 = Shumway.AVM2;
|
|
}(Shumway || (Shumway = {})));
|
|
Shumway.AVM2.Runtime.enableVerifier.value = true;
|
|
release = true;
|
|
var avm2Root = SHUMWAY_ROOT + 'avm2/';
|
|
var builtinPath = avm2Root + 'generated/builtin/builtin.abc';
|
|
var avm1Path = avm2Root + 'generated/avm1lib/avm1lib.abc';
|
|
var BinaryFileReader = function binaryFileReader() {
|
|
function constructor(url, responseType) {
|
|
this.url = url;
|
|
this.responseType = responseType || 'arraybuffer';
|
|
}
|
|
constructor.prototype = {
|
|
readAll: function (progress, complete) {
|
|
var url = this.url;
|
|
var xhr = new XMLHttpRequest();
|
|
var async = true;
|
|
xhr.open('GET', this.url, async);
|
|
xhr.responseType = this.responseType;
|
|
if (progress) {
|
|
xhr.onprogress = function (event) {
|
|
progress(xhr.response, event.loaded, event.total);
|
|
};
|
|
}
|
|
xhr.onreadystatechange = function (event) {
|
|
if (xhr.readyState === 4) {
|
|
if (xhr.status !== 200 && xhr.status !== 0) {
|
|
unexpected('Path: ' + url + ' not found.');
|
|
complete(null, xhr.statusText);
|
|
return;
|
|
}
|
|
complete(xhr.response);
|
|
}
|
|
};
|
|
xhr.send(null);
|
|
},
|
|
readAsync: function (ondata, onerror, onopen, oncomplete, onhttpstatus) {
|
|
var xhr = new XMLHttpRequest({
|
|
mozSystem: true
|
|
});
|
|
var url = this.url;
|
|
xhr.open(this.method || 'GET', url, true);
|
|
var isNotProgressive;
|
|
try {
|
|
xhr.responseType = 'moz-chunked-arraybuffer';
|
|
isNotProgressive = xhr.responseType !== 'moz-chunked-arraybuffer';
|
|
} catch (e) {
|
|
isNotProgressive = true;
|
|
}
|
|
if (isNotProgressive) {
|
|
xhr.responseType = 'arraybuffer';
|
|
}
|
|
xhr.onprogress = function (e) {
|
|
if (isNotProgressive)
|
|
return;
|
|
ondata(new Uint8Array(xhr.response), {
|
|
loaded: e.loaded,
|
|
total: e.total
|
|
});
|
|
};
|
|
xhr.onreadystatechange = function (event) {
|
|
if (xhr.readyState === 2 && onhttpstatus) {
|
|
onhttpstatus(url, xhr.status, xhr.getAllResponseHeaders());
|
|
}
|
|
if (xhr.readyState === 4) {
|
|
if (xhr.status !== 200 && xhr.status !== 0) {
|
|
onerror(xhr.statusText);
|
|
}
|
|
if (isNotProgressive) {
|
|
var buffer = xhr.response;
|
|
ondata(new Uint8Array(buffer), {
|
|
loaded: buffer.byteLength,
|
|
total: buffer.byteLength
|
|
});
|
|
}
|
|
if (oncomplete) {
|
|
oncomplete();
|
|
}
|
|
} else if (xhr.readyState === 2 && onopen) {
|
|
onopen();
|
|
}
|
|
};
|
|
xhr.send(null);
|
|
}
|
|
};
|
|
return constructor;
|
|
}();
|
|
var libraryAbcs;
|
|
function grabAbc(abcName) {
|
|
var entry = libraryScripts[abcName];
|
|
if (entry) {
|
|
var offset = entry.offset;
|
|
var length = entry.length;
|
|
return new AbcFile(new Uint8Array(libraryAbcs, offset, length), abcName);
|
|
}
|
|
return null;
|
|
}
|
|
var avm2;
|
|
function createAVM2(builtinPath, libraryPath, avm1Path, sysMode, appMode, next) {
|
|
avm2 = new AVM2(sysMode, appMode, loadAVM1);
|
|
var builtinAbc, avm1Abc;
|
|
AVM2.loadPlayerglobal(libraryPath.abcs, libraryPath.catalog).then(function () {
|
|
new BinaryFileReader(builtinPath).readAll(null, function (buffer) {
|
|
builtinAbc = new AbcFile(new Uint8Array(buffer), 'builtin.abc');
|
|
executeAbc();
|
|
});
|
|
});
|
|
function loadAVM1(next) {
|
|
new BinaryFileReader(avm1Path).readAll(null, function (buffer) {
|
|
avm1Abc = new AbcFile(new Uint8Array(buffer), 'avm1.abc');
|
|
;
|
|
avm2.systemDomain.executeAbc(avm1Abc);
|
|
next();
|
|
});
|
|
}
|
|
function executeAbc() {
|
|
avm2.builtinsLoaded = false;
|
|
avm2.systemDomain.onMessage.register('classCreated', Stubs.onClassCreated);
|
|
avm2.systemDomain.executeAbc(builtinAbc);
|
|
avm2.builtinsLoaded = true;
|
|
console.info(JSON.stringify(Counter.toJSON()));
|
|
console.timeEnd('Load AVM2');
|
|
next(avm2);
|
|
}
|
|
}
|
|
{
|
|
var MAX_SNAP_DRAW_SCALE_TO_CACHE = 8;
|
|
var CACHE_SNAP_DRAW_AFTER = 3;
|
|
var BitmapDefinition = function () {
|
|
function setBitmapData(value) {
|
|
if (this._bitmapData) {
|
|
this._bitmapData._changeNotificationTarget = null;
|
|
}
|
|
this._bitmapData = value;
|
|
if (this._bitmapData) {
|
|
this._bitmapData._changeNotificationTarget = this;
|
|
}
|
|
if (value) {
|
|
var canvas = value._drawable;
|
|
this._bbox = {
|
|
xMin: 0,
|
|
yMin: 0,
|
|
xMax: canvas.width * 20,
|
|
yMax: canvas.height * 20
|
|
};
|
|
} else {
|
|
this._bbox = {
|
|
xMin: 0,
|
|
yMin: 0,
|
|
xMax: 0,
|
|
yMax: 0
|
|
};
|
|
}
|
|
this._drawableChanged();
|
|
this._invalidateBounds();
|
|
this._invalidateTransform();
|
|
}
|
|
return {
|
|
__class__: 'flash.display.Bitmap',
|
|
draw: function (ctx, ratio, colorTransform) {
|
|
if (!this._bitmapData) {
|
|
return;
|
|
}
|
|
var scaledImage;
|
|
ctx.save();
|
|
if (this._pixelSnapping === 'auto' || this._pixelSnapping === 'always') {
|
|
var transform = this._getConcatenatedTransform(null, true);
|
|
var EPSILON = 0.001;
|
|
var aInt = Math.abs(Math.round(transform.a));
|
|
var dInt = Math.abs(Math.round(transform.d));
|
|
var snapPixels;
|
|
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) {
|
|
if (aInt === 1 && dInt === 1) {
|
|
snapPixels = true;
|
|
} else {
|
|
var sizeKey = aInt + 'x' + dInt;
|
|
if (this._snapImageCache.size !== sizeKey) {
|
|
this._snapImageCache.size = sizeKey;
|
|
this._snapImageCache.hits = 0;
|
|
this._snapImageCache.image = null;
|
|
}
|
|
if (++this._snapImageCache.hits === CACHE_SNAP_DRAW_AFTER) {
|
|
this._cacheSnapImage(sizeKey, aInt, dInt);
|
|
}
|
|
scaledImage = this._snapImageCache.image;
|
|
snapPixels = !(!scaledImage);
|
|
}
|
|
} else {
|
|
snapPixels = false;
|
|
}
|
|
if (snapPixels) {
|
|
ctx.setTransform(transform.a < 0 ? -1 : 1, 0, 0, transform.d < 0 ? -1 : 1, transform.tx / 20 | 0, transform.ty / 20 | 0);
|
|
}
|
|
}
|
|
colorTransform.setAlpha(ctx, true);
|
|
ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = this._smoothing;
|
|
ctx.drawImage(scaledImage || this._bitmapData._getDrawable(), 0, 0);
|
|
ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = false;
|
|
ctx.restore();
|
|
traceRenderer.value && frameWriter.writeLn('Bitmap.draw() snapping: ' + this._pixelSnapping + ', dimensions: ' + this._bitmapData._drawable.width + ' x ' + this._bitmapData._drawable.height);
|
|
},
|
|
_drawableChanged: function () {
|
|
this._invalidate();
|
|
this._snapImageCache.image = null;
|
|
this._snapImageCache.hints = 0;
|
|
},
|
|
_cacheSnapImage: function (sizeKey, xScale, yScale) {
|
|
Counter.count('Cache scaled image');
|
|
var original = this._bitmapData._getDrawable();
|
|
var canvas = document.createElement('canvas');
|
|
canvas.width = xScale * original.width;
|
|
canvas.height = yScale * original.height;
|
|
var ctx = canvas.getContext('2d');
|
|
ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = this._smoothing;
|
|
ctx.drawImage(original, 0, 0, original.width, original.height, 0, 0, canvas.width, canvas.height);
|
|
var cache = this._snapImageCache;
|
|
var image = document.createElement('img');
|
|
cache._tmp = [
|
|
canvas,
|
|
image
|
|
];
|
|
if ('toBlob' in canvas) {
|
|
canvas.toBlob(function (blob) {
|
|
if (cache.size !== sizeKey) {
|
|
return;
|
|
}
|
|
image.onload = function () {
|
|
URL.revokeObjectURL(blob);
|
|
if (cache.size === sizeKey) {
|
|
cache.image = image;
|
|
}
|
|
};
|
|
image.src = URL.createObjectURL(blob);
|
|
});
|
|
} else {
|
|
image.onload = function () {
|
|
if (cache.size === sizeKey) {
|
|
cache.image = image;
|
|
}
|
|
};
|
|
image.src = canvas.toDataURL();
|
|
}
|
|
},
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
ctor: function (bitmapData, pixelSnapping, smoothing) {
|
|
if (pixelSnapping === 'never' || pixelSnapping === 'always') {
|
|
this._pixelSnapping = pixelSnapping;
|
|
} else {
|
|
this._pixelSnapping = 'auto';
|
|
}
|
|
this._smoothing = !(!smoothing);
|
|
this._snapImageCache = {
|
|
hits: 0,
|
|
size: '',
|
|
image: null
|
|
};
|
|
if (!bitmapData && this.symbol) {
|
|
var symbol = this.symbol;
|
|
bitmapData = new flash.display.BitmapData(symbol.width, symbol.height, true, 0);
|
|
bitmapData._ctx.imageSmoothingEnabled = this._smoothing;
|
|
bitmapData._ctx.mozImageSmoothingEnabled = this._smoothing;
|
|
bitmapData._ctx.drawImage(symbol.img, 0, 0);
|
|
bitmapData._ctx.imageSmoothingEnabled = false;
|
|
bitmapData._ctx.mozImageSmoothingEnabled = false;
|
|
}
|
|
setBitmapData.call(this, bitmapData || null);
|
|
},
|
|
pixelSnapping: {
|
|
get: function pixelSnapping() {
|
|
return this._pixelSnapping;
|
|
},
|
|
set: function pixelSnapping(value) {
|
|
this._pixelSnapping = value;
|
|
}
|
|
},
|
|
smoothing: {
|
|
get: function smoothing() {
|
|
return this._smoothing;
|
|
},
|
|
set: function smoothing(value) {
|
|
this._smoothing = value;
|
|
}
|
|
},
|
|
bitmapData: {
|
|
get: function bitmapData() {
|
|
return this._bitmapData;
|
|
},
|
|
set: setBitmapData
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
}
|
|
var CACHE_DRAWABLE_AFTER = 10;
|
|
var BitmapDataDefinition = function () {
|
|
function replaceRect(ctx, x, y, w, h, alpha) {
|
|
if (alpha < 255) {
|
|
ctx.clearRect(x, y, w, h);
|
|
}
|
|
if (alpha > 0) {
|
|
ctx.fillRect(x, y, w, h);
|
|
}
|
|
}
|
|
var def = {
|
|
__class__: 'flash.display.BitmapData',
|
|
initialize: function () {
|
|
this._changeNotificationTarget = null;
|
|
this._locked = false;
|
|
this._requested = 0;
|
|
this._cache = null;
|
|
if (this.symbol) {
|
|
this._img = this.symbol.img;
|
|
this._skipCopyToCanvas = this.symbol.skipCopyToCanvas;
|
|
}
|
|
},
|
|
_checkCanvas: function () {
|
|
if (this._drawable === null)
|
|
throw ArgumentError();
|
|
},
|
|
ctor: function (width, height, transparent, backgroundColor) {
|
|
if (this._img) {
|
|
width = this._img.naturalWidth || this._img.width;
|
|
height = this._img.naturalHeight || this._img.height;
|
|
} else if (isNaN(width + height) || width <= 0 || height <= 0) {
|
|
throwError('ArgumentError', Errors.ArgumentError);
|
|
}
|
|
this._transparent = transparent === undefined ? true : !(!transparent);
|
|
this._backgroundColor = backgroundColor === undefined ? 4294967295 : backgroundColor;
|
|
if (!this._transparent) {
|
|
this._backgroundColor |= 4278190080;
|
|
}
|
|
if (this._skipCopyToCanvas) {
|
|
this._drawable = this._img;
|
|
} else {
|
|
var canvas = document.createElement('canvas');
|
|
this._ctx = canvas.getContext('2d');
|
|
canvas.width = width | 0;
|
|
canvas.height = height | 0;
|
|
this._drawable = canvas;
|
|
if (!this._transparent || !this._img && this._backgroundColor) {
|
|
this.fillRect(new flash.geom.Rectangle(0, 0, width | 0, height | 0), this._backgroundColor);
|
|
}
|
|
if (this._img) {
|
|
this._ctx.drawImage(this._img, 0, 0);
|
|
}
|
|
}
|
|
},
|
|
dispose: function () {
|
|
this._ctx = null;
|
|
this._drawable.width = 0;
|
|
this._drawable.height = 0;
|
|
this._drawable = null;
|
|
},
|
|
draw: function (source, matrix, colorTransform, blendMode, clipRect, smoothing) {
|
|
this._checkCanvas();
|
|
var ctx = this._ctx;
|
|
ctx.save();
|
|
ctx.beginPath();
|
|
if (clipRect && clipRect.width > 0 && clipRect.height > 0) {
|
|
ctx.rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
|
|
ctx.clip();
|
|
}
|
|
if (matrix) {
|
|
ctx.transform(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
|
|
}
|
|
ctx.globalCompositeOperation = getBlendModeName(blendMode);
|
|
ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = !(!smoothing);
|
|
if (flash.display.BitmapData.class.isInstanceOf(source)) {
|
|
ctx.drawImage(source._drawable, 0, 0);
|
|
} else {
|
|
new RenderVisitor(source, ctx, null, true).startFragment(matrix);
|
|
}
|
|
ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = false;
|
|
ctx.restore();
|
|
this._invalidate();
|
|
},
|
|
fillRect: function (rect, color) {
|
|
this._checkCanvas();
|
|
if (!this._transparent) {
|
|
color |= 4278190080;
|
|
}
|
|
var ctx = this._ctx;
|
|
ctx.fillStyle = argbUintToStr(color);
|
|
replaceRect(ctx, rect.x, rect.y, rect.width, rect.height, color >>> 24 & 255);
|
|
this._invalidate();
|
|
},
|
|
getPixel: function (x, y) {
|
|
this._checkCanvas();
|
|
var data = this._ctx.getImageData(x, y, 1, 1).data;
|
|
return dataToRGB(data);
|
|
},
|
|
getPixel32: function (x, y) {
|
|
this._checkCanvas();
|
|
var data = this._ctx.getImageData(x, y, 1, 1).data;
|
|
return dataToARGB(data);
|
|
},
|
|
_invalidate: function (changeRect) {
|
|
if (changeRect) {
|
|
somewhatImplemented('BitmapData._invalidate(changeRect)');
|
|
}
|
|
if (this._locked) {
|
|
return;
|
|
}
|
|
if (this._changeNotificationTarget) {
|
|
this._changeNotificationTarget._drawableChanged();
|
|
}
|
|
this._requested = 0;
|
|
this._cache = null;
|
|
},
|
|
_getDrawable: function () {
|
|
if (this._img === this._drawable) {
|
|
return this._drawable;
|
|
}
|
|
this._requested++;
|
|
if (this._requested >= CACHE_DRAWABLE_AFTER) {
|
|
if (!this._cache) {
|
|
Counter.count('Cache drawable');
|
|
var img = document.createElement('img');
|
|
if ('toBlob' in this._drawable) {
|
|
this._drawable.toBlob(function (blob) {
|
|
img.src = URL.createObjectURL(blob);
|
|
img.onload = function () {
|
|
URL.revokeObjectURL(blob);
|
|
};
|
|
});
|
|
} else {
|
|
img.src = this._drawable.toDataURL();
|
|
}
|
|
this._cache = img;
|
|
}
|
|
if (this._cache.width > 0) {
|
|
return this._cache;
|
|
}
|
|
}
|
|
return this._drawable;
|
|
},
|
|
setPixel: function (x, y, color) {
|
|
this.fillRect({
|
|
x: x,
|
|
y: y,
|
|
width: 1,
|
|
height: 1
|
|
}, color | 4278190080);
|
|
this._invalidate();
|
|
},
|
|
setPixel32: function (x, y, color) {
|
|
this.fillRect({
|
|
x: x,
|
|
y: y,
|
|
width: 1,
|
|
height: 1
|
|
}, color);
|
|
this._invalidate();
|
|
},
|
|
copyPixels: function copyPixels(sourceBitmapData, sourceRect, destPoint, alphaBitmapData, alphaPoint, mergeAlpha) {
|
|
if (alphaBitmapData) {
|
|
notImplemented('BitmapData.copyPixels w/ alpha');
|
|
}
|
|
var w = sourceRect.width;
|
|
var h = sourceRect.height;
|
|
var sx = sourceRect.x;
|
|
var sy = sourceRect.y;
|
|
var dx = destPoint.x;
|
|
var dy = destPoint.y;
|
|
var offsetx = -Math.min(0, sx, dx);
|
|
var offsety = -Math.min(0, sy, dy);
|
|
var correctionw = Math.min(0, this._ctx.canvas.width - dx - w, sourceBitmapData._drawable.width - sx - w) - offsetx;
|
|
var correctionh = Math.min(0, this._ctx.canvas.height - dy - h, sourceBitmapData._drawable.height - sy - h) - offsety;
|
|
if (!mergeAlpha) {
|
|
this._ctx.clearRect(dx, dy, w, h);
|
|
}
|
|
if (w + correctionw > 0 && h + correctionh > 0) {
|
|
this._ctx.drawImage(sourceBitmapData._drawable, sx + offsetx, sy + offsety, w + correctionw, h + correctionh, dx + offsetx, dy + offsety, w + correctionw, h + correctionh);
|
|
}
|
|
this._invalidate();
|
|
},
|
|
lock: function lock() {
|
|
this._locked = true;
|
|
},
|
|
unlock: function unlock(changeRect) {
|
|
this._locked = false;
|
|
this._invalidate(changeRect);
|
|
},
|
|
clone: function () {
|
|
this._checkCanvas();
|
|
var bd = new flash.display.BitmapData(this._drawable.width, this._drawable.height, true, 0);
|
|
bd._ctx.drawImage(this._drawable, 0, 0);
|
|
return bd;
|
|
},
|
|
scroll: function (x, y) {
|
|
this._checkCanvas();
|
|
this._ctx.draw(this._drawable, x, y);
|
|
this._ctx.save();
|
|
var color = this._img ? 0 : this._backgroundColor;
|
|
if (!this._transparent) {
|
|
color |= 4278190080;
|
|
}
|
|
var alpha = color >>> 24 & 255;
|
|
this._ctx.fillStyle = argbUintToStr(color);
|
|
var w = this._drawable.width;
|
|
var h = this._drawable.height;
|
|
if (x > 0) {
|
|
replaceRect(this._ctx, 0, 0, x, h, alpha);
|
|
} else if (x < 0) {
|
|
replaceRect(this._ctx, w + x, 0, -x, h, alpha);
|
|
}
|
|
if (y > 0) {
|
|
replaceRect(this._ctx, 0, 0, w, y, alpha);
|
|
} else if (y < 0) {
|
|
replaceRect(this._ctx, h + y, w, -y, alpha);
|
|
}
|
|
this._ctx.restore();
|
|
this._invalidate();
|
|
},
|
|
get width() {
|
|
return this._drawable.width;
|
|
},
|
|
get height() {
|
|
return this._drawable.height;
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
ctor: def.ctor,
|
|
fillRect: def.fillRect,
|
|
dispose: def.dispose,
|
|
getPixel: def.getPixel,
|
|
getPixel32: def.getPixel32,
|
|
setPixel: def.setPixel,
|
|
setPixel32: def.setPixel32,
|
|
copyPixels: def.copyPixels,
|
|
lock: def.lock,
|
|
unlock: def.unlock,
|
|
draw: def.draw,
|
|
clone: def.clone,
|
|
scroll: def.scroll,
|
|
width: desc(def, 'width'),
|
|
height: desc(def, 'height')
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
function dataToRGB(data) {
|
|
return data[0] << 16 | data[1] << 8 | data[2];
|
|
}
|
|
function dataToARGB(data) {
|
|
return data[3] << 24 | dataToRGB(data);
|
|
}
|
|
var DisplayObjectDefinition = function () {
|
|
var blendModes;
|
|
var nextInstanceId = 1;
|
|
function generateName() {
|
|
return 'instance' + nextInstanceId++;
|
|
}
|
|
var broadcastedEvents = {
|
|
advanceFrame: false,
|
|
enterFrame: true,
|
|
constructChildren: false,
|
|
frameConstructed: true,
|
|
executeFrame: false,
|
|
exitFrame: true,
|
|
render: true
|
|
};
|
|
var point = {
|
|
x: 0,
|
|
y: 0
|
|
};
|
|
var def = {
|
|
__class__: 'flash.display.DisplayObject',
|
|
initialize: function () {
|
|
var blendModeClass = flash.display.BlendMode.class;
|
|
this._alpha = 1;
|
|
this._animated = false;
|
|
this._bbox = null;
|
|
this._bitmap = null;
|
|
this._blendMode = blendModeClass.NORMAL;
|
|
this._bounds = {
|
|
xMin: 0,
|
|
xMax: 0,
|
|
yMin: 0,
|
|
yMax: 0,
|
|
invalid: true
|
|
};
|
|
this._cacheAsBitmap = false;
|
|
this._children = [];
|
|
this._clipDepth = null;
|
|
this._currentTransform = {
|
|
a: 1,
|
|
b: 0,
|
|
c: 0,
|
|
d: 1,
|
|
tx: 0,
|
|
ty: 0
|
|
};
|
|
this._concatenatedTransform = {
|
|
a: 1,
|
|
b: 0,
|
|
c: 0,
|
|
d: 1,
|
|
tx: 0,
|
|
ty: 0,
|
|
invalid: true
|
|
};
|
|
this._current3DTransform = null;
|
|
this._cxform = null;
|
|
this._graphics = null;
|
|
this._filters = [];
|
|
this._loader = null;
|
|
this._mouseChildren = true;
|
|
this._mouseOver = false;
|
|
this._mouseX = 0;
|
|
this._mouseY = 0;
|
|
this._name = null;
|
|
this._opaqueBackground = null;
|
|
this._owned = false;
|
|
this._parent = null;
|
|
this._rotation = 0;
|
|
this._rotationCos = 1;
|
|
this._rotationSin = 0;
|
|
this._scale9Grid = null;
|
|
this._scaleX = 1;
|
|
this._scaleY = 1;
|
|
this._stage = null;
|
|
this._visible = true;
|
|
this._hidden = false;
|
|
this._wasCachedAsBitmap = false;
|
|
this._destroyed = false;
|
|
this._maskedObject = null;
|
|
this._scrollRect = null;
|
|
this._invalid = false;
|
|
this._region = null;
|
|
this._level = -1;
|
|
this._index = -1;
|
|
this._depth = -1;
|
|
this._isContainer = false;
|
|
this._invisible = false;
|
|
this._zindex = 0;
|
|
blendModes = [
|
|
blendModeClass.NORMAL,
|
|
blendModeClass.NORMAL,
|
|
blendModeClass.LAYER,
|
|
blendModeClass.MULTIPLY,
|
|
blendModeClass.SCREEN,
|
|
blendModeClass.LIGHTEN,
|
|
blendModeClass.DARKEN,
|
|
blendModeClass.DIFFERENCE,
|
|
blendModeClass.ADD,
|
|
blendModeClass.SUBTRACT,
|
|
blendModeClass.INVERT,
|
|
blendModeClass.ALPHA,
|
|
blendModeClass.ERASE,
|
|
blendModeClass.OVERLAY,
|
|
blendModeClass.HARDLIGHT,
|
|
blendModeClass.SHADER
|
|
];
|
|
var s = this.symbol;
|
|
if (s) {
|
|
this._animated = s.animated || false;
|
|
this._bbox = s.bbox || null;
|
|
this._blendMode = this._resolveBlendMode(s.blendMode);
|
|
this._children = s.children || [];
|
|
this._clipDepth = s.clipDepth || null;
|
|
this._cxform = s.cxform || null;
|
|
this._loader = s.loader || null;
|
|
this._name = s.name || null;
|
|
this._owned = s.owned || false;
|
|
this._parent = s.parent || null;
|
|
this._level = isNaN(s.level) ? -1 : s.level;
|
|
this._index = isNaN(s.index) ? -1 : s.index;
|
|
this._depth = isNaN(s.depth) ? -1 : s.depth;
|
|
this._root = s.root || null;
|
|
this._stage = s.stage || null;
|
|
var scale9Grid = s.scale9Grid;
|
|
if (scale9Grid) {
|
|
this._scale9Grid = new flash.geom.Rectangle(scale9Grid.left, scale9Grid.top, scale9Grid.right - scale9Grid.left, scale9Grid.bottom - scale9Grid.top);
|
|
}
|
|
var matrix = s.currentTransform;
|
|
if (matrix) {
|
|
this._setTransformMatrix(matrix, false);
|
|
}
|
|
}
|
|
this._accessibilityProperties = null;
|
|
var self = this;
|
|
this._onBroadcastMessage = function (type) {
|
|
var listeners = self._listeners;
|
|
if (listeners[type]) {
|
|
self._dispatchEvent(type);
|
|
}
|
|
};
|
|
},
|
|
_addEventListener: function addEventListener(type, listener, useCapture, priority) {
|
|
if (broadcastedEvents[type] === false) {
|
|
avm2.systemDomain.onMessage.register(type, listener);
|
|
return;
|
|
}
|
|
if (type in broadcastedEvents && !this._listeners[type]) {
|
|
avm2.systemDomain.onMessage.register(type, this._onBroadcastMessage);
|
|
}
|
|
this._addEventListenerImpl(type, listener, useCapture, priority);
|
|
},
|
|
_removeEventListener: function addEventListener(type, listener, useCapture) {
|
|
if (broadcastedEvents[type] === false) {
|
|
avm2.systemDomain.onMessage.unregister(type, listener);
|
|
return;
|
|
}
|
|
this._removeEventListenerImpl(type, listener, useCapture);
|
|
if (type in broadcastedEvents && !this._listeners[type]) {
|
|
avm2.systemDomain.onMessage.unregister(type, this._onBroadcastMessage);
|
|
}
|
|
},
|
|
_resolveBlendMode: function (blendModeNumeric) {
|
|
return blendModes[blendModeNumeric] || flash.display.BlendMode.class.NORMAL;
|
|
},
|
|
_getConcatenatedTransform: function (targetCoordSpace, toDeviceSpace) {
|
|
var stage = this._stage;
|
|
if (this === this._stage) {
|
|
return toDeviceSpace ? this._concatenatedTransform : this._currentTransform;
|
|
}
|
|
if (targetCoordSpace === this._parent) {
|
|
return this._currentTransform;
|
|
}
|
|
var invalidNode = null;
|
|
var m, m2, targetCoordMatrix;
|
|
var currentNode = this;
|
|
while (currentNode !== stage) {
|
|
if (currentNode._concatenatedTransform.invalid) {
|
|
invalidNode = currentNode;
|
|
}
|
|
if (currentNode === targetCoordSpace) {
|
|
targetCoordMatrix = currentNode._concatenatedTransform;
|
|
}
|
|
currentNode = currentNode._parent;
|
|
}
|
|
if (invalidNode) {
|
|
if (this._parent === stage) {
|
|
m = this._concatenatedTransform;
|
|
m2 = this._currentTransform;
|
|
m.a = m2.a;
|
|
m.b = m2.b;
|
|
m.c = m2.c;
|
|
m.d = m2.d;
|
|
m.tx = m2.tx;
|
|
m.ty = m2.ty;
|
|
} else {
|
|
var stack = [];
|
|
var currentNode = this;
|
|
while (currentNode !== invalidNode) {
|
|
stack.push(currentNode);
|
|
currentNode = currentNode._parent;
|
|
}
|
|
var node = invalidNode;
|
|
do {
|
|
var parent = node._parent;
|
|
m = node._concatenatedTransform;
|
|
m2 = node._currentTransform;
|
|
if (parent) {
|
|
if (parent !== stage) {
|
|
var m3 = parent._concatenatedTransform;
|
|
m.a = m2.a * m3.a + m2.b * m3.c;
|
|
m.b = m2.a * m3.b + m2.b * m3.d;
|
|
m.c = m2.c * m3.a + m2.d * m3.c;
|
|
m.d = m2.d * m3.d + m2.c * m3.b;
|
|
m.tx = m2.tx * m3.a + m3.tx + m2.ty * m3.c;
|
|
m.ty = m2.ty * m3.d + m3.ty + m2.tx * m3.b;
|
|
}
|
|
} else {
|
|
m.a = m2.a;
|
|
m.b = m2.b;
|
|
m.c = m2.c;
|
|
m.d = m2.d;
|
|
m.tx = m2.tx;
|
|
m.ty = m2.ty;
|
|
}
|
|
m.invalid = false;
|
|
var nextNode = stack.pop();
|
|
var children = node._children;
|
|
for (var i = 0; i < children.length; i++) {
|
|
var child = children[i];
|
|
if (child !== nextNode) {
|
|
child._concatenatedTransform.invalid = true;
|
|
}
|
|
}
|
|
node = nextNode;
|
|
} while (node);
|
|
}
|
|
} else {
|
|
m = this._concatenatedTransform;
|
|
}
|
|
if (targetCoordSpace && targetCoordSpace !== this._stage) {
|
|
m2 = targetCoordMatrix || targetCoordSpace._getConcatenatedTransform(null, false);
|
|
var a = 1, b = 0, c = 0, d = 1, tx = 0, ty = 0;
|
|
if (m2.b || m2.c) {
|
|
var det = 1 / (m2.a * m2.d - m2.b * m2.c);
|
|
a = m2.d * det;
|
|
b = -m2.b * det;
|
|
c = -m2.c * det;
|
|
d = m2.a * det;
|
|
tx = -(a * m2.tx + c * m2.ty);
|
|
ty = -(b * m2.tx + d * m2.ty);
|
|
} else {
|
|
a = 1 / m2.a;
|
|
d = 1 / m2.d;
|
|
tx = m2.tx * -a;
|
|
ty = m2.ty * -d;
|
|
}
|
|
return {
|
|
a: a * m.a + c * m.b,
|
|
b: b * m.a + d * m.b,
|
|
c: a * m.c + c * m.d,
|
|
d: b * m.c + d * m.d,
|
|
tx: a * m.tx + c * m.ty + tx,
|
|
ty: b * m.tx + d * m.ty + ty
|
|
};
|
|
}
|
|
if (toDeviceSpace && stage) {
|
|
m2 = stage._concatenatedTransform;
|
|
return {
|
|
a: m.a * m2.a,
|
|
b: m.b * m2.d,
|
|
c: m.c * m2.a,
|
|
d: m.d * m2.d,
|
|
tx: m.tx * m2.a + m2.tx,
|
|
ty: m.ty * m2.d + m2.ty
|
|
};
|
|
}
|
|
return m;
|
|
},
|
|
_applyCurrentTransform: function (pt) {
|
|
var m = this._getConcatenatedTransform(null, false);
|
|
var x = pt.x;
|
|
var y = pt.y;
|
|
pt.x = m.a * x + m.c * y + m.tx | 0;
|
|
pt.y = m.d * y + m.b * x + m.ty | 0;
|
|
},
|
|
_applyConcatenatedInverseTransform: function (pt) {
|
|
var m = this._getConcatenatedTransform(null, false);
|
|
var det = 1 / (m.a * m.d - m.b * m.c);
|
|
var x = pt.x - m.tx;
|
|
var y = pt.y - m.ty;
|
|
pt.x = (m.d * x - m.c * y) * det | 0;
|
|
pt.y = (m.a * y - m.b * x) * det | 0;
|
|
},
|
|
_hitTest: function (use_xy, x, y, useShape, hitTestObject) {
|
|
if (use_xy) {
|
|
point.x = x;
|
|
point.y = y;
|
|
this._applyConcatenatedInverseTransform(point);
|
|
var b = this._getContentBounds();
|
|
if (!(point.x >= b.xMin && point.x < b.xMax && point.y >= b.yMin && point.y < b.yMax)) {
|
|
return false;
|
|
}
|
|
if (!useShape || !this._graphics) {
|
|
return true;
|
|
}
|
|
if (this._graphics) {
|
|
var subpaths = this._graphics._paths;
|
|
for (var i = 0, n = subpaths.length; i < n; i++) {
|
|
var path = subpaths[i];
|
|
if (path.isPointInPath(point.x, point.y)) {
|
|
return true;
|
|
}
|
|
if (path.strokeStyle) {
|
|
var strokePath = path._strokePath;
|
|
if (!strokePath) {
|
|
strokePath = path.strokePath(path.drawingStyles);
|
|
path._strokePath = strokePath;
|
|
}
|
|
if (strokePath.isPointInPath(point.x, point.y)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var children = this._children;
|
|
for (var i = 0, n = children.length; i < n; i++) {
|
|
var child = children[i];
|
|
if (child._hitTest && child._hitTest(true, x, y, true, null)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
var b1 = this.getBounds(this._stage);
|
|
var b2 = hitTestObject.getBounds(hitTestObject._stage);
|
|
x = Math.max(b1.xMin, b2.xMin);
|
|
y = Math.max(b1.yMin, b2.yMin);
|
|
var width = Math.min(b1.xMax, b2.xMax) - x;
|
|
var height = Math.min(b1.yMax, b2.yMax) - y;
|
|
return width > 0 && height > 0;
|
|
},
|
|
_invalidate: function () {
|
|
this._invalid = true;
|
|
},
|
|
_invalidateBounds: function () {
|
|
var currentNode = this;
|
|
while (currentNode && !currentNode._bounds.invalid) {
|
|
currentNode._bounds.invalid = true;
|
|
currentNode = currentNode._parent;
|
|
}
|
|
},
|
|
_invalidateTransform: function () {
|
|
this._concatenatedTransform.invalid = true;
|
|
if (this._parent) {
|
|
this._parent._invalidateBounds();
|
|
}
|
|
},
|
|
_setTransformMatrix: function (matrix, convertToTwips) {
|
|
var a = matrix.a;
|
|
var b = matrix.b;
|
|
var c = matrix.c;
|
|
var d = matrix.d;
|
|
var tx, ty;
|
|
if (convertToTwips) {
|
|
tx = matrix.tx * 20 | 0;
|
|
ty = matrix.ty * 20 | 0;
|
|
} else {
|
|
tx = matrix.tx;
|
|
ty = matrix.ty;
|
|
}
|
|
var angle = a !== 0 ? Math.atan(b / a) : b > 0 ? Math.PI / 2 : -Math.PI / 2;
|
|
this._rotation = angle * 180 / Math.PI;
|
|
this._rotationCos = Math.cos(angle);
|
|
this._rotationSin = Math.sin(angle);
|
|
var sx = Math.sqrt(a * a + b * b);
|
|
this._scaleX = a > 0 ? sx : -sx;
|
|
var sy = Math.sqrt(d * d + c * c);
|
|
this._scaleY = d > 0 ? sy : -sy;
|
|
var transform = this._currentTransform;
|
|
transform.a = a;
|
|
transform.b = b;
|
|
transform.c = c;
|
|
transform.d = d;
|
|
transform.tx = tx;
|
|
transform.ty = ty;
|
|
this._invalidateTransform();
|
|
},
|
|
get accessibilityProperties() {
|
|
return this._accessibilityProperties;
|
|
},
|
|
set accessibilityProperties(val) {
|
|
this._accessibilityProperties = val;
|
|
},
|
|
get alpha() {
|
|
return this._alpha;
|
|
},
|
|
set alpha(val) {
|
|
if (val === this._alpha) {
|
|
return;
|
|
}
|
|
this._invalidate();
|
|
this._alpha = val;
|
|
this._animated = false;
|
|
},
|
|
get blendMode() {
|
|
return this._blendMode;
|
|
},
|
|
set blendMode(val) {
|
|
if (blendModes.indexOf(val) >= 0) {
|
|
this._blendMode = val;
|
|
} else {
|
|
throwError('ArgumentError', Errors.InvalidEnumError, 'blendMode');
|
|
}
|
|
this._animated = false;
|
|
},
|
|
get cacheAsBitmap() {
|
|
return this._cacheAsBitmap;
|
|
},
|
|
set cacheAsBitmap(val) {
|
|
this._cacheAsBitmap = this._filters.length ? true : val;
|
|
this._animated = false;
|
|
},
|
|
get filters() {
|
|
return this._filters;
|
|
},
|
|
set filters(val) {
|
|
if (val.length) {
|
|
if (!this._filters.length)
|
|
this._wasCachedAsBitmap = this._cacheAsBitmap;
|
|
this._cacheAsBitmap = true;
|
|
} else {
|
|
this._cacheAsBitmap = this._wasCachedAsBitmap;
|
|
}
|
|
this._filters = val;
|
|
this._animated = false;
|
|
},
|
|
get height() {
|
|
var bounds = this._getContentBounds();
|
|
var t = this._currentTransform;
|
|
return Math.abs(t.b) * (bounds.xMax - bounds.xMin) + Math.abs(t.d) * (bounds.yMax - bounds.yMin) | 0;
|
|
},
|
|
set height(val) {
|
|
if (val < 0) {
|
|
return;
|
|
}
|
|
var u = Math.abs(this._rotationCos);
|
|
var v = Math.abs(this._rotationSin);
|
|
var bounds = this._getContentBounds();
|
|
var baseHeight = v * (bounds.xMax - bounds.xMin) + u * (bounds.yMax - bounds.yMin);
|
|
if (!baseHeight) {
|
|
return;
|
|
}
|
|
var baseWidth = u * (bounds.xMax - bounds.xMin) + v * (bounds.yMax - bounds.yMin);
|
|
this.scaleX = this.width / baseWidth;
|
|
this.scaleY = val / baseHeight;
|
|
},
|
|
get loaderInfo() {
|
|
return this._loader && this._loader._contentLoaderInfo || this._parent.loaderInfo;
|
|
},
|
|
get mask() {
|
|
return this._mask;
|
|
},
|
|
set mask(val) {
|
|
if (this._mask === val) {
|
|
return;
|
|
}
|
|
this._invalidate();
|
|
if (val && val._maskedObject) {
|
|
val._maskedObject.mask = null;
|
|
}
|
|
this._mask = val;
|
|
if (val) {
|
|
val._maskedObject = this;
|
|
}
|
|
this._animated = false;
|
|
},
|
|
get name() {
|
|
return this._name || (this._name = generateName());
|
|
},
|
|
set name(val) {
|
|
this._name = val;
|
|
},
|
|
get mouseX() {
|
|
if (!this._stage) {
|
|
return 0;
|
|
}
|
|
point.x = this._stage._mouseX;
|
|
point.y = this._stage._mouseY;
|
|
this._applyConcatenatedInverseTransform(point);
|
|
return point.x;
|
|
},
|
|
get mouseY() {
|
|
if (!this._stage) {
|
|
return 0;
|
|
}
|
|
point.x = this._stage._mouseX;
|
|
point.y = this._stage._mouseY;
|
|
this._applyConcatenatedInverseTransform(point);
|
|
return point.y;
|
|
},
|
|
get opaqueBackground() {
|
|
return this._opaqueBackground;
|
|
},
|
|
set opaqueBackground(val) {
|
|
this._opaqueBackground = val;
|
|
this._animated = false;
|
|
},
|
|
get parent() {
|
|
return this._index > -1 ? this._parent : null;
|
|
},
|
|
get root() {
|
|
return this._stage && this._stage._root;
|
|
},
|
|
get rotation() {
|
|
return this._rotation;
|
|
},
|
|
set rotation(val) {
|
|
val %= 360;
|
|
if (val > 180) {
|
|
val -= 360;
|
|
}
|
|
if (val === this._rotation)
|
|
return;
|
|
this._invalidate();
|
|
this._invalidateTransform();
|
|
this._rotation = val;
|
|
var u, v;
|
|
switch (val) {
|
|
case 0:
|
|
case 360:
|
|
u = 1, v = 0;
|
|
break;
|
|
case 90:
|
|
case -270:
|
|
u = 0, v = 1;
|
|
break;
|
|
case 180:
|
|
case -180:
|
|
u = -1, v = 0;
|
|
break;
|
|
case 270:
|
|
case -90:
|
|
u = 0, v = -1;
|
|
break;
|
|
default:
|
|
var angle = this._rotation / 180 * Math.PI;
|
|
u = Math.cos(angle);
|
|
v = Math.sin(angle);
|
|
break;
|
|
}
|
|
this._rotationCos = u;
|
|
this._rotationSin = v;
|
|
var m = this._currentTransform;
|
|
m.a = u * this._scaleX;
|
|
m.b = v * this._scaleX;
|
|
m.c = -v * this._scaleY;
|
|
m.d = u * this._scaleY;
|
|
this._animated = false;
|
|
},
|
|
get rotationX() {
|
|
return 0;
|
|
},
|
|
set rotationX(val) {
|
|
somewhatImplemented('DisplayObject.rotationX');
|
|
},
|
|
get rotationY() {
|
|
return 0;
|
|
},
|
|
set rotationY(val) {
|
|
somewhatImplemented('DisplayObject.rotationY');
|
|
},
|
|
get rotationZ() {
|
|
return this.rotation;
|
|
},
|
|
set rotationZ(val) {
|
|
this.rotation = val;
|
|
somewhatImplemented('DisplayObject.rotationZ');
|
|
},
|
|
get stage() {
|
|
return this._stage;
|
|
},
|
|
get scaleX() {
|
|
return this._scaleX;
|
|
},
|
|
set scaleX(val) {
|
|
if (val === this._scaleX)
|
|
return;
|
|
this._invalidate();
|
|
this._invalidateTransform();
|
|
this._scaleX = val;
|
|
var m = this._currentTransform;
|
|
m.a = this._rotationCos * val;
|
|
m.b = this._rotationSin * val;
|
|
this._animated = false;
|
|
},
|
|
get scaleY() {
|
|
return this._scaleY;
|
|
},
|
|
set scaleY(val) {
|
|
if (val === this._scaleY)
|
|
return;
|
|
this._invalidate();
|
|
this._invalidateTransform();
|
|
this._scaleY = val;
|
|
var m = this._currentTransform;
|
|
m.c = -this._rotationSin * val;
|
|
m.d = this._rotationCos * val;
|
|
this._animated = false;
|
|
},
|
|
get scaleZ() {
|
|
return 1;
|
|
},
|
|
set scaleZ(val) {
|
|
somewhatImplemented('DisplayObject.scaleZ');
|
|
},
|
|
get scale9Grid() {
|
|
return this._scale9Grid;
|
|
},
|
|
set scale9Grid(val) {
|
|
somewhatImplemented('DisplayObject.scale9Grid');
|
|
this._scale9Grid = val;
|
|
this._animated = false;
|
|
},
|
|
get scrollRect() {
|
|
return this._scrollRect;
|
|
},
|
|
set scrollRect(val) {
|
|
somewhatImplemented('DisplayObject.scrollRect');
|
|
this._scrollRect = val;
|
|
},
|
|
get transform() {
|
|
return new flash.geom.Transform(this);
|
|
},
|
|
set transform(val) {
|
|
var transform = this.transform;
|
|
transform.colorTransform = val.colorTransform;
|
|
if (val.matrix3D) {
|
|
transform.matrix3D = val.matrix3D;
|
|
} else {
|
|
transform.matrix = val.matrix;
|
|
}
|
|
},
|
|
get visible() {
|
|
return this._visible;
|
|
},
|
|
set visible(val) {
|
|
if (val === this._visible)
|
|
return;
|
|
this._invalidate();
|
|
this._visible = val;
|
|
this._animated = false;
|
|
},
|
|
get width() {
|
|
var bounds = this._getContentBounds();
|
|
var t = this._currentTransform;
|
|
return Math.abs(t.a) * (bounds.xMax - bounds.xMin) + Math.abs(t.c) * (bounds.yMax - bounds.yMin) | 0;
|
|
},
|
|
set width(val) {
|
|
if (val < 0) {
|
|
return;
|
|
}
|
|
var u = Math.abs(this._rotationCos);
|
|
var v = Math.abs(this._rotationSin);
|
|
var bounds = this._getContentBounds();
|
|
var baseWidth = u * (bounds.xMax - bounds.xMin) + v * (bounds.yMax - bounds.yMin);
|
|
if (!baseWidth) {
|
|
return;
|
|
}
|
|
var baseHeight = v * (bounds.xMax - bounds.xMin) + u * (bounds.yMax - bounds.yMin);
|
|
this.scaleY = this.height / baseHeight;
|
|
this.scaleX = val / baseWidth;
|
|
},
|
|
get x() {
|
|
return this._currentTransform.tx;
|
|
},
|
|
set x(val) {
|
|
if (val === this._currentTransform.tx) {
|
|
return;
|
|
}
|
|
this._invalidate();
|
|
this._invalidateTransform();
|
|
this._currentTransform.tx = val;
|
|
this._animated = false;
|
|
},
|
|
get y() {
|
|
return this._currentTransform.ty;
|
|
},
|
|
set y(val) {
|
|
if (val === this._currentTransform.ty) {
|
|
return;
|
|
}
|
|
this._invalidate();
|
|
this._invalidateTransform();
|
|
this._currentTransform.ty = val;
|
|
this._animated = false;
|
|
},
|
|
get z() {
|
|
return 0;
|
|
},
|
|
set z(val) {
|
|
somewhatImplemented('DisplayObject.z');
|
|
},
|
|
_getContentBounds: function () {
|
|
var bounds = this._bounds;
|
|
if (bounds.invalid) {
|
|
var bbox = this._bbox;
|
|
var xMin = Number.MAX_VALUE;
|
|
var xMax = Number.MIN_VALUE;
|
|
var yMin = Number.MAX_VALUE;
|
|
var yMax = Number.MIN_VALUE;
|
|
if (bbox) {
|
|
xMin = bbox.xMin;
|
|
xMax = bbox.xMax;
|
|
yMin = bbox.yMin;
|
|
yMax = bbox.yMax;
|
|
} else {
|
|
var children = this._children;
|
|
var numChildren = children.length;
|
|
for (var i = 0; i < numChildren; i++) {
|
|
var child = children[i];
|
|
if (!flash.display.DisplayObject.class.isInstanceOf(child)) {
|
|
continue;
|
|
}
|
|
var b = child.getBounds(this);
|
|
var x1 = b.xMin;
|
|
var y1 = b.yMin;
|
|
var x2 = b.xMax;
|
|
var y2 = b.yMax;
|
|
xMin = Math.min(xMin, x1, x2);
|
|
xMax = Math.max(xMax, x1, x2);
|
|
yMin = Math.min(yMin, y1, y2);
|
|
yMax = Math.max(yMax, y1, y2);
|
|
}
|
|
if (this._graphics) {
|
|
var b = this._graphics._getBounds(true);
|
|
if (b.xMin !== b.xMax && b.yMin !== b.yMax) {
|
|
var x1 = b.xMin;
|
|
var y1 = b.yMin;
|
|
var x2 = b.xMax;
|
|
var y2 = b.yMax;
|
|
xMin = Math.min(xMin, x1, x2);
|
|
xMax = Math.max(xMax, x1, x2);
|
|
yMin = Math.min(yMin, y1, y2);
|
|
yMax = Math.max(yMax, y1, y2);
|
|
}
|
|
}
|
|
}
|
|
if (xMin === Number.MAX_VALUE) {
|
|
xMin = xMax = yMin = yMax = 0;
|
|
}
|
|
bounds.xMin = xMin;
|
|
bounds.xMax = xMax;
|
|
bounds.yMin = yMin;
|
|
bounds.yMax = yMax;
|
|
bounds.invalid = false;
|
|
}
|
|
return bounds;
|
|
},
|
|
_getRegion: function getRegion(targetCoordSpace) {
|
|
var b;
|
|
var filters = this._filters;
|
|
if (filters.length) {
|
|
var xMin = Number.MAX_VALUE;
|
|
var xMax = Number.MIN_VALUE;
|
|
var yMin = Number.MAX_VALUE;
|
|
var yMax = Number.MIN_VALUE;
|
|
if (this._graphics) {
|
|
b = this._graphics._getBounds(true);
|
|
if (b) {
|
|
xMin = b.xMin;
|
|
xMax = b.xMax;
|
|
yMin = b.yMin;
|
|
yMax = b.yMax;
|
|
}
|
|
}
|
|
var children = this._children;
|
|
for (var i = 0; i < children.length; i++) {
|
|
var child = children[i];
|
|
b = children[i]._getRegion(this);
|
|
if (b.xMin < xMin) {
|
|
xMin = b.xMin;
|
|
}
|
|
if (b.xMax > xMax) {
|
|
xMax = b.xMax;
|
|
}
|
|
if (b.yMin < yMin) {
|
|
yMin = b.yMin;
|
|
}
|
|
if (b.yMax > yMax) {
|
|
yMax = b.yMax;
|
|
}
|
|
}
|
|
if (xMin === Number.MAX_VALUE) {
|
|
return {
|
|
xMin: 0,
|
|
xMax: 0,
|
|
yMin: 0,
|
|
yMax: 0
|
|
};
|
|
}
|
|
b = {
|
|
xMin: xMin,
|
|
xMax: xMax,
|
|
yMin: yMin,
|
|
yMax: yMax
|
|
};
|
|
for (var i = 0; i < filters.length; i++) {
|
|
filters[i]._updateFilterBounds(b);
|
|
}
|
|
} else {
|
|
b = this._graphics ? this._graphics._getBounds(true) : this._getContentBounds();
|
|
}
|
|
return this._getTransformedRect(b, targetCoordSpace);
|
|
},
|
|
getBounds: function (targetCoordSpace) {
|
|
return this._getTransformedRect(this._getContentBounds(), targetCoordSpace);
|
|
},
|
|
_getTransformedRect: function (rect, targetCoordSpace) {
|
|
if (!targetCoordSpace || targetCoordSpace === this) {
|
|
return rect;
|
|
}
|
|
var xMin = rect.xMin;
|
|
var xMax = rect.xMax;
|
|
var yMin = rect.yMin;
|
|
var yMax = rect.yMax;
|
|
if (xMax - xMin === 0 || yMax - yMin === 0) {
|
|
return {
|
|
xMin: 0,
|
|
yMin: 0,
|
|
xMax: 0,
|
|
yMax: 0
|
|
};
|
|
}
|
|
var m = targetCoordSpace && !flash.display.DisplayObject.class.isInstanceOf(targetCoordSpace) ? targetCoordSpace : this._getConcatenatedTransform(targetCoordSpace, false);
|
|
var x0 = m.a * xMin + m.c * yMin + m.tx | 0;
|
|
var y0 = m.b * xMin + m.d * yMin + m.ty | 0;
|
|
var x1 = m.a * xMax + m.c * yMin + m.tx | 0;
|
|
var y1 = m.b * xMax + m.d * yMin + m.ty | 0;
|
|
var x2 = m.a * xMax + m.c * yMax + m.tx | 0;
|
|
var y2 = m.b * xMax + m.d * yMax + m.ty | 0;
|
|
var x3 = m.a * xMin + m.c * yMax + m.tx | 0;
|
|
var y3 = m.b * xMin + m.d * yMax + m.ty | 0;
|
|
var tmp = 0;
|
|
if (x0 > x1) {
|
|
tmp = x0;
|
|
x0 = x1;
|
|
x1 = tmp;
|
|
}
|
|
if (x2 > x3) {
|
|
tmp = x2;
|
|
x2 = x3;
|
|
x3 = tmp;
|
|
}
|
|
xMin = x0 < x2 ? x0 : x2;
|
|
xMax = x1 > x3 ? x1 : x3;
|
|
if (y0 > y1) {
|
|
tmp = y0;
|
|
y0 = y1;
|
|
y1 = tmp;
|
|
}
|
|
if (y2 > y3) {
|
|
tmp = y2;
|
|
y2 = y3;
|
|
y3 = tmp;
|
|
}
|
|
yMin = y0 < y2 ? y0 : y2;
|
|
yMax = y1 > y3 ? y1 : y3;
|
|
return {
|
|
xMin: xMin,
|
|
yMin: yMin,
|
|
xMax: xMax,
|
|
yMax: yMax
|
|
};
|
|
},
|
|
hitTestObject: function (obj) {
|
|
return this._hitTest(false, 0, 0, false, obj);
|
|
},
|
|
hitTestPoint: function (x, y, shapeFlag) {
|
|
return this._hitTest(true, x, y, shapeFlag, null);
|
|
},
|
|
destroy: function () {
|
|
if (this._destroyed) {
|
|
return;
|
|
}
|
|
this._destroyed = true;
|
|
this.cleanupBroadcastListeners();
|
|
},
|
|
cleanupBroadcastListeners: function () {
|
|
var listenerLists = this._listeners;
|
|
for (var type in listenerLists) {
|
|
avm2.systemDomain.onMessage.unregister(type, this._onBroadcastMessage);
|
|
}
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
root: desc(def, 'root'),
|
|
stage: desc(def, 'stage'),
|
|
name: desc(def, 'name'),
|
|
parent: desc(def, 'parent'),
|
|
mask: desc(def, 'mask'),
|
|
visible: desc(def, 'visible'),
|
|
x: {
|
|
get: function x() {
|
|
return this.x / 20;
|
|
},
|
|
set: function x(value) {
|
|
this.x = value * 20 | 0;
|
|
}
|
|
},
|
|
y: {
|
|
get: function y() {
|
|
return this.y / 20;
|
|
},
|
|
set: function y(value) {
|
|
this.y = value * 20 | 0;
|
|
}
|
|
},
|
|
z: {
|
|
get: function z() {
|
|
return this.z / 20;
|
|
},
|
|
set: function z(value) {
|
|
this.z = value * 20 | 0;
|
|
}
|
|
},
|
|
scaleX: desc(def, 'scaleX'),
|
|
scaleY: desc(def, 'scaleY'),
|
|
scaleZ: desc(def, 'scaleZ'),
|
|
mouseX: {
|
|
get: function mouseX() {
|
|
return this.mouseX / 20;
|
|
},
|
|
set: function mouseX(value) {
|
|
this.mouseX = value * 20 | 0;
|
|
}
|
|
},
|
|
mouseY: {
|
|
get: function mouseY() {
|
|
return this.mouseY / 20;
|
|
},
|
|
set: function mouseY(value) {
|
|
this.mouseY = value * 20 | 0;
|
|
}
|
|
},
|
|
rotation: desc(def, 'rotation'),
|
|
rotationX: desc(def, 'rotationX'),
|
|
rotationY: desc(def, 'rotationY'),
|
|
rotationZ: desc(def, 'rotationZ'),
|
|
alpha: desc(def, 'alpha'),
|
|
width: {
|
|
get: function width() {
|
|
return this.width / 20;
|
|
},
|
|
set: function width(value) {
|
|
this.width = value * 20 | 0;
|
|
}
|
|
},
|
|
height: {
|
|
get: function height() {
|
|
return this.height / 20;
|
|
},
|
|
set: function height(value) {
|
|
this.height = value * 20 | 0;
|
|
}
|
|
},
|
|
_hitTest: function (use_xy, x, y, useShape, hitTestObject) {
|
|
x = x * 20 | 0;
|
|
y = y * 20 | 0;
|
|
return this._hitTest(use_xy, x, y, useShape, hitTestObject);
|
|
},
|
|
cacheAsBitmap: desc(def, 'cacheAsBitmap'),
|
|
opaqueBackground: desc(def, 'opaqueBackground'),
|
|
scrollRect: desc(def, 'scrollRect'),
|
|
filters: desc(def, 'filters'),
|
|
blendMode: desc(def, 'blendMode'),
|
|
transform: desc(def, 'transform'),
|
|
scale9Grid: desc(def, 'scale9Grid'),
|
|
loaderInfo: desc(def, 'loaderInfo'),
|
|
accessibilityProperties: desc(def, 'accessibilityProperties'),
|
|
globalToLocal: function (pt) {
|
|
point.x = pt.x * 20 | 0;
|
|
point.y = pt.y * 20 | 0;
|
|
this._applyConcatenatedInverseTransform(point);
|
|
return new flash.geom.Point(point.x / 20, point.y / 20);
|
|
},
|
|
localToGlobal: function (pt) {
|
|
point.x = pt.x * 20 | 0;
|
|
point.y = pt.y * 20 | 0;
|
|
this._applyCurrentTransform(point);
|
|
return new flash.geom.Point(point.x / 20, point.y / 20);
|
|
},
|
|
getBounds: function (targetCoordSpace) {
|
|
var bounds = this.getBounds(targetCoordSpace);
|
|
return new flash.geom.Rectangle(bounds.xMin / 20, bounds.yMin / 20, (bounds.xMax - bounds.xMin) / 20, (bounds.yMax - bounds.yMin) / 20);
|
|
},
|
|
getRect: function (targetCoordSpace) {
|
|
somewhatImplemented('DisplayObject.getRect');
|
|
var bounds = this.getBounds(targetCoordSpace);
|
|
return new flash.geom.Rectangle(bounds.xMin / 20, bounds.yMin / 20, (bounds.xMax - bounds.xMin) / 20, (bounds.yMax - bounds.yMin) / 20);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var DisplayObjectContainerDefinition = function () {
|
|
var def = {
|
|
get mouseChildren() {
|
|
return this._mouseChildren;
|
|
},
|
|
set mouseChildren(val) {
|
|
this._mouseChildren = val;
|
|
},
|
|
get numChildren() {
|
|
return this._children.length;
|
|
},
|
|
get tabChildren() {
|
|
return this._tabChildren;
|
|
},
|
|
set tabChildren(val) {
|
|
this._tabChildren = val;
|
|
},
|
|
get textSnapshot() {
|
|
notImplemented();
|
|
},
|
|
addChild: function (child) {
|
|
return this.addChildAt(child, this._children.length);
|
|
},
|
|
addChildAt: function (child, index) {
|
|
if (child === this) {
|
|
throwError('ArgumentError', Errors.CantAddSelfError);
|
|
}
|
|
if (child._parent === this) {
|
|
return this.setChildIndex(child, index);
|
|
}
|
|
var children = this._children;
|
|
if (index < 0 || index > children.length) {
|
|
throwError('RangeError', Errors.ParamRangeError);
|
|
}
|
|
if (child._index > -1) {
|
|
var LoaderClass = avm2.systemDomain.getClass('flash.display.Loader');
|
|
if (LoaderClass.isInstanceOf(child._parent)) {
|
|
def.removeChild.call(child._parent, child);
|
|
} else {
|
|
child._parent.removeChild(child);
|
|
}
|
|
}
|
|
if (!this._sparse) {
|
|
for (var i = children.length; i && i > index; i--) {
|
|
children[i - 1]._index++;
|
|
}
|
|
}
|
|
children.splice(index, 0, child);
|
|
child._invalidateTransform();
|
|
child._owned = false;
|
|
child._parent = this;
|
|
child._stage = this._stage;
|
|
child._index = index;
|
|
child._dispatchEvent('added', undefined, true);
|
|
if (this._stage) {
|
|
this._stage._addToStage(child);
|
|
}
|
|
return child;
|
|
},
|
|
areInaccessibleObjectsUnderPoint: function (pt) {
|
|
notImplemented();
|
|
},
|
|
contains: function (child) {
|
|
return child._parent === this;
|
|
},
|
|
getChildAt: function (index) {
|
|
var children = this._children;
|
|
if (index < 0 || index > children.length) {
|
|
throwError('RangeError', Errors.ParamRangeError);
|
|
}
|
|
var child = children[index];
|
|
if (!flash.display.DisplayObject.class.isInstanceOf(child)) {
|
|
return null;
|
|
}
|
|
return child;
|
|
},
|
|
getChildByName: function (name) {
|
|
var children = this._children;
|
|
for (var i = 0, n = children.length; i < n; i++) {
|
|
var child = children[i];
|
|
if (child.name === name) {
|
|
return this.getChildAt(i);
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
getChildIndex: function (child) {
|
|
if (child._parent !== this) {
|
|
throwError('ArgumentError', Errors.NotAChildError);
|
|
}
|
|
return this._sparse ? this._children.indexOf(child) : child._index;
|
|
},
|
|
getObjectsUnderPoint: function (pt) {
|
|
notImplemented();
|
|
},
|
|
removeChild: function (child) {
|
|
if (child._parent !== this) {
|
|
throwError('ArgumentError', Errors.NotAChildError);
|
|
}
|
|
return this.removeChildAt(this.getChildIndex(child));
|
|
},
|
|
removeChildAt: function (index) {
|
|
var children = this._children;
|
|
if (index < 0 || index >= children.length) {
|
|
throwError('RangeError', Errors.ParamRangeError);
|
|
}
|
|
var child = children[index];
|
|
child._dispatchEvent('removed', undefined, true);
|
|
if (this._stage) {
|
|
this._stage._removeFromStage(child);
|
|
}
|
|
if (!this._sparse) {
|
|
for (var i = children.length; i && i > index; i--) {
|
|
children[i - 1]._index--;
|
|
}
|
|
}
|
|
children.splice(index, 1);
|
|
child._invalidateTransform();
|
|
child._owned = false;
|
|
child._parent = null;
|
|
child._index = -1;
|
|
return child;
|
|
},
|
|
setChildIndex: function (child, index) {
|
|
if (child._parent !== this) {
|
|
throwError('ArgumentError', Errors.NotAChildError);
|
|
}
|
|
var currentIndex = this.getChildIndex(child);
|
|
if (currentIndex === index) {
|
|
return;
|
|
}
|
|
var children = this._children;
|
|
if (index < 0 || index > children.length) {
|
|
throwError('RangeError', Errors.ParamRangeError);
|
|
}
|
|
children.splice(currentIndex, 1);
|
|
children.splice(index, 0, child);
|
|
if (!this._sparse) {
|
|
var i = currentIndex < index ? currentIndex : index;
|
|
while (i < children.length) {
|
|
children[i]._index = i++;
|
|
}
|
|
}
|
|
child._owned = false;
|
|
child._invalidate();
|
|
return child;
|
|
},
|
|
removeChildren: function (beginIndex, endIndex) {
|
|
beginIndex = arguments.length < 1 ? 0 : beginIndex | 0;
|
|
endIndex = arguments.length < 2 ? 2147483647 : endIndex | 0;
|
|
var numChildren = this._children.length;
|
|
if (beginIndex < 0 || endIndex < 0 || endIndex < beginIndex) {
|
|
throwError('RangeError', Errors.ParamRangeError);
|
|
}
|
|
if (numChildren === 0) {
|
|
return;
|
|
}
|
|
if (endIndex > numChildren - 1) {
|
|
endIndex = numChildren - 1;
|
|
}
|
|
var count = endIndex - beginIndex + 1;
|
|
while (count--) {
|
|
this.removeChildAt(beginIndex);
|
|
}
|
|
},
|
|
swapChildren: function (child1, child2) {
|
|
if (child1._parent !== this || child2._parent !== this) {
|
|
throwError('ArgumentError', Errors.NotAChildError);
|
|
}
|
|
this.swapChildrenAt(this.getChildIndex(child1), this.getChildIndex(child2));
|
|
},
|
|
swapChildrenAt: function (index1, index2) {
|
|
var children = this._children;
|
|
var numChildren = children.length;
|
|
if (index1 < 0 || index1 > numChildren || index2 < 0 || index2 > numChildren) {
|
|
throwError('RangeError', Errors.ParamRangeError);
|
|
}
|
|
var child1 = children[index1];
|
|
var child2 = children[index2];
|
|
children[index1] = child2;
|
|
children[index2] = child1;
|
|
child1._index = index2;
|
|
child2._index = index1;
|
|
child1._owned = false;
|
|
child2._owned = false;
|
|
child1._invalidate();
|
|
child2._invalidate();
|
|
},
|
|
destroy: function () {
|
|
if (this._destroyed) {
|
|
return;
|
|
}
|
|
this._destroyed = true;
|
|
this._children.forEach(function (child) {
|
|
if (child.destroy) {
|
|
child.destroy();
|
|
}
|
|
});
|
|
this.cleanupBroadcastListeners();
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.initialize = function () {
|
|
this._mouseChildren = true;
|
|
this._tabChildren = true;
|
|
this._sparse = false;
|
|
this._isContainer = true;
|
|
};
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
numChildren: desc(def, 'numChildren'),
|
|
tabChildren: desc(def, 'tabChildren'),
|
|
mouseChildren: desc(def, 'mouseChildren'),
|
|
textSnapshot: desc(def, 'textSnapshot'),
|
|
addChild: def.addChild,
|
|
addChildAt: def.addChildAt,
|
|
removeChild: def.removeChild,
|
|
removeChildAt: def.removeChildAt,
|
|
getChildIndex: def.getChildIndex,
|
|
setChildIndex: def.setChildIndex,
|
|
getChildAt: def.getChildAt,
|
|
getChildByName: def.getChildByName,
|
|
contains: def.contains,
|
|
swapChildrenAt: def.swapChildrenAt,
|
|
swapChildren: def.swapChildren,
|
|
removeChildren: def.removeChildren
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var FrameLabelDefinition = function () {
|
|
return {
|
|
__class__: 'flash.display.FrameLabel',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
ctor: function ctor(name, frame) {
|
|
this._name = name;
|
|
this._frame = frame;
|
|
},
|
|
name: {
|
|
get: function name() {
|
|
return this._name;
|
|
}
|
|
},
|
|
frame: {
|
|
get: function frame() {
|
|
return this._frame;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var GraphicsDefinition = function () {
|
|
var GRAPHICS_PATH_WINDING_EVEN_ODD = 'evenOdd';
|
|
var GRAPHICS_PATH_WINDING_NON_ZERO = 'nonZero';
|
|
var def = {
|
|
__class__: 'flash.display.Graphics',
|
|
initialize: function () {
|
|
this._paths = [];
|
|
this.beginPath();
|
|
this._bitmap = null;
|
|
this._parent = 0;
|
|
this.bbox = null;
|
|
this.strokeBbox = null;
|
|
},
|
|
_invalidate: function () {
|
|
this.bbox = null;
|
|
this.strokeBbox = null;
|
|
this._parent._invalidate();
|
|
this._parent._invalidateBounds();
|
|
},
|
|
beginPath: function () {
|
|
var oldPath = this._currentPath;
|
|
if (oldPath && (oldPath.commands.length === 0 || oldPath.commands.length === 1 && oldPath.commands[0] === SHAPE_MOVE_TO)) {
|
|
return;
|
|
}
|
|
var path = this._currentPath = new ShapePath(null, null);
|
|
this._paths.push(path);
|
|
if (oldPath) {
|
|
path.fillStyle = oldPath.fillStyle;
|
|
path.lineStyle = oldPath.lineStyle;
|
|
path.fillRule = oldPath.fillRule;
|
|
}
|
|
},
|
|
_drawPathObject: function (path) {
|
|
if (path.__class__ === 'flash.display.GraphicsPath')
|
|
this.drawPath(path.commands, path.data, path.winding);
|
|
else if (path.__class__ === 'flash.display.GraphicsTrianglePath')
|
|
this.drawTriangles(path.vertices, path.indices, path.uvtData, path.culling);
|
|
},
|
|
draw: function (ctx, clip, ratio, colorTransform) {
|
|
var paths = this._paths;
|
|
for (var i = 0; i < paths.length; i++) {
|
|
paths[i].draw(ctx, clip, ratio, colorTransform);
|
|
}
|
|
},
|
|
beginFill: function (color, alpha) {
|
|
if (alpha === undefined)
|
|
alpha = 1;
|
|
this.beginPath();
|
|
this._currentPath.fillStyle = alpha ? {
|
|
style: rgbIntAlphaToStr(color, alpha)
|
|
} : null;
|
|
},
|
|
beginGradientFill: function (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos) {
|
|
var style = createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos);
|
|
this.beginPath();
|
|
this._currentPath.fillStyle = style;
|
|
},
|
|
beginBitmapFill: function (bitmap, matrix, repeat, smooth) {
|
|
this.beginPath();
|
|
repeat = repeat !== false;
|
|
this._currentPath.fillStyle = createPatternStyle(bitmap, matrix, repeat, !(!smooth));
|
|
},
|
|
clear: function () {
|
|
this._invalidate();
|
|
this._paths = [];
|
|
this._currentPath = null;
|
|
this.beginPath();
|
|
},
|
|
copyFrom: function (sourceGraphics) {
|
|
notImplemented('Graphics#copyFrom');
|
|
},
|
|
cubicCurveTo: function (cp1x, cp1y, cp2x, cp2y, x, y) {
|
|
this._invalidate();
|
|
this._currentPath.cubicCurveTo(cp1x * 20 | 0, cp1y * 20 | 0, cp2x * 20 | 0, cp2y * 20 | 0, x * 20 | 0, y * 20 | 0);
|
|
},
|
|
curveTo: function (cpx, cpy, x, y) {
|
|
this._invalidate();
|
|
this._currentPath.curveTo(cpx * 20 | 0, cpy * 20 | 0, x * 20 | 0, y * 20 | 0);
|
|
},
|
|
drawCircle: function (x, y, radius) {
|
|
var radius2 = radius * 2;
|
|
this.drawRoundRect(x - radius, y - radius, radius2, radius2, radius2, radius2);
|
|
},
|
|
drawEllipse: function (x, y, width, height) {
|
|
this.drawRoundRect(x, y, width, height, width, height);
|
|
},
|
|
drawPath: function (commands, data, winding) {
|
|
this._invalidate();
|
|
this.beginPath();
|
|
this._currentPath.fillRule = winding || GRAPHICS_PATH_WINDING_EVEN_ODD;
|
|
this._currentPath.commands = commands;
|
|
this._currentPath.data = data;
|
|
},
|
|
drawRect: function (x, y, w, h) {
|
|
if (isNaN(w + h))
|
|
throwError('ArgumentError', Errors.InvalidParamError);
|
|
this._invalidate();
|
|
this._currentPath.rect(x * 20 | 0, y * 20 | 0, w * 20 | 0, h * 20 | 0);
|
|
},
|
|
drawRoundRect: function (x, y, w, h, ellipseWidth, ellipseHeight) {
|
|
if (isNaN(w + h + ellipseWidth) || ellipseHeight !== undefined && isNaN(ellipseHeight)) {
|
|
throwError('ArgumentError', Errors.InvalidParamError);
|
|
}
|
|
this._invalidate();
|
|
if (ellipseHeight === undefined) {
|
|
ellipseHeight = ellipseWidth;
|
|
}
|
|
x = x * 20 | 0;
|
|
y = y * 20 | 0;
|
|
w = w * 20 | 0;
|
|
h = h * 20 | 0;
|
|
if (!ellipseHeight || !ellipseWidth) {
|
|
this._currentPath.rect(x, y, w, h);
|
|
return;
|
|
}
|
|
var radiusX = ellipseWidth / 2 * 20 | 0;
|
|
var radiusY = ellipseHeight / 2 * 20 | 0;
|
|
var hw = w / 2 | 0;
|
|
var hh = h / 2 | 0;
|
|
if (radiusX > hw) {
|
|
radiusX = hw;
|
|
}
|
|
if (radiusY > hh) {
|
|
radiusY = hh;
|
|
}
|
|
if (hw === radiusX && hh === radiusY) {
|
|
if (radiusX === radiusY)
|
|
this._currentPath.circle(x + radiusX, y + radiusY, radiusX);
|
|
else
|
|
this._currentPath.ellipse(x + radiusX, y + radiusY, radiusX, radiusY);
|
|
return;
|
|
}
|
|
var right = x + w;
|
|
var bottom = y + h;
|
|
var xlw = x + radiusX;
|
|
var xrw = right - radiusX;
|
|
var ytw = y + radiusY;
|
|
var ybw = bottom - radiusY;
|
|
this._currentPath.moveTo(right, ybw);
|
|
this._currentPath.curveTo(right, bottom, xrw, bottom);
|
|
this._currentPath.lineTo(xlw, bottom);
|
|
this._currentPath.curveTo(x, bottom, x, ybw);
|
|
this._currentPath.lineTo(x, ytw);
|
|
this._currentPath.curveTo(x, y, xlw, y);
|
|
this._currentPath.lineTo(xrw, y);
|
|
this._currentPath.curveTo(right, y, right, ytw);
|
|
this._currentPath.lineTo(right, ybw);
|
|
},
|
|
drawRoundRectComplex: function (x, y, w, h, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius) {
|
|
if (isNaN(w + h + topLeftRadius + topRightRadius + bottomLeftRadius + bottomRightRadius)) {
|
|
throwError('ArgumentError', Errors.InvalidParamError);
|
|
}
|
|
this._invalidate();
|
|
x = x * 20 | 0;
|
|
y = y * 20 | 0;
|
|
w = w * 20 | 0;
|
|
h = h * 20 | 0;
|
|
if (!topLeftRadius && !topRightRadius && !bottomLeftRadius && !bottomRightRadius) {
|
|
this._currentPath.rect(x, y, w, h);
|
|
return;
|
|
}
|
|
topLeftRadius = topLeftRadius * 20 | 0;
|
|
topRightRadius = topRightRadius * 20 | 0;
|
|
bottomLeftRadius = bottomLeftRadius * 20 | 0;
|
|
bottomRightRadius = bottomRightRadius * 20 | 0;
|
|
var right = x + w;
|
|
var bottom = y + h;
|
|
var xtl = x + topLeftRadius;
|
|
this._currentPath.moveTo(right, bottom - bottomRightRadius);
|
|
this._currentPath.curveTo(right, bottom, right - bottomRightRadius, bottom);
|
|
this._currentPath.lineTo(x + bottomLeftRadius, bottom);
|
|
this._currentPath.curveTo(x, bottom, x, bottom - bottomLeftRadius);
|
|
this._currentPath.lineTo(x, y + topLeftRadius);
|
|
this._currentPath.curveTo(x, y, xtl, y);
|
|
this._currentPath.lineTo(right - topRightRadius, y);
|
|
this._currentPath.curveTo(right, y, right, y + topRightRadius);
|
|
this._currentPath.lineTo(right, bottom - bottomRightRadius);
|
|
},
|
|
drawTriangles: function (vertices, indices, uvtData, cullingStr) {
|
|
if (vertices === null || vertices.length === 0) {
|
|
return;
|
|
}
|
|
var numVertices = vertices.length / 2;
|
|
var numTriangles = 0;
|
|
if (indices) {
|
|
if (indices.length % 3) {
|
|
throwError('ArgumentError', Errors.InvalidParamError);
|
|
} else {
|
|
numTriangles = indices.length / 3;
|
|
}
|
|
} else {
|
|
if (vertices.length % 6) {
|
|
throwError('ArgumentError', Errors.InvalidParamError);
|
|
} else {
|
|
numTriangles = vertices.length / 6;
|
|
}
|
|
}
|
|
var numStrides = 0;
|
|
if (uvtData) {
|
|
if (uvtData.length == numVertices * 2) {
|
|
numStrides = 2;
|
|
} else if (uvtData.length == numVertices * 3) {
|
|
numStrides = 3;
|
|
} else {
|
|
throwError('ArgumentError', Errors.InvalidParamError);
|
|
}
|
|
}
|
|
var culling = 0;
|
|
if (cullingStr === 'none') {
|
|
culling = 0;
|
|
} else if (cullingStr === 'negative') {
|
|
culling = -1;
|
|
} else if (cullingStr === 'positive') {
|
|
culling = 1;
|
|
} else {
|
|
throwError('ArgumentError', Errors.InvalidEnumError, 'culling');
|
|
}
|
|
notImplemented('Graphics#drawTriangles');
|
|
},
|
|
endFill: function () {
|
|
this.beginPath();
|
|
this._currentPath.fillStyle = null;
|
|
},
|
|
lineBitmapStyle: function (bitmap, matrix, repeat, smooth) {
|
|
this.beginPath();
|
|
this._currentPath.lineStyle = createPatternStyle(bitmap, matrix, repeat, smooth);
|
|
},
|
|
lineGradientStyle: function (type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos) {
|
|
var style = createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos);
|
|
this.beginPath();
|
|
this._currentPath.lineStyle = style;
|
|
},
|
|
lineStyle: function (width, color, alpha, pxHinting, scale, cap, joint, mlimit) {
|
|
this.beginPath();
|
|
if (width) {
|
|
if (alpha === undefined)
|
|
alpha = 1;
|
|
if (mlimit === undefined)
|
|
mlimit = 3;
|
|
this._currentPath.lineStyle = {
|
|
style: rgbIntAlphaToStr(color, alpha),
|
|
lineCap: cap || 'round',
|
|
lineJoin: cap || 'round',
|
|
width: width * 20 | 0,
|
|
miterLimit: mlimit * 2
|
|
};
|
|
} else {
|
|
this._currentPath.lineStyle = null;
|
|
}
|
|
},
|
|
lineTo: function (x, y) {
|
|
this._invalidate();
|
|
this._currentPath.lineTo(x * 20 | 0, y * 20 | 0);
|
|
},
|
|
moveTo: function (x, y) {
|
|
this._currentPath.moveTo(x * 20 | 0, y * 20 | 0);
|
|
},
|
|
_getBounds: function (includeStroke) {
|
|
var bbox = includeStroke ? this.strokeBbox : this.bbox;
|
|
if (bbox) {
|
|
return bbox;
|
|
}
|
|
var subpaths = this._paths;
|
|
var xMins = [], yMins = [], xMaxs = [], yMaxs = [];
|
|
for (var i = 0, n = subpaths.length; i < n; i++) {
|
|
var path = subpaths[i];
|
|
if (path.commands.length) {
|
|
var b = path.getBounds(includeStroke);
|
|
if (b) {
|
|
xMins.push(b.xMin);
|
|
yMins.push(b.yMin);
|
|
xMaxs.push(b.xMax);
|
|
yMaxs.push(b.yMax);
|
|
}
|
|
}
|
|
}
|
|
if (xMins.length === 0) {
|
|
bbox = {
|
|
xMin: 0,
|
|
yMin: 0,
|
|
xMax: 0,
|
|
yMax: 0
|
|
};
|
|
} else {
|
|
bbox = {
|
|
xMin: Math.min.apply(Math, xMins),
|
|
yMin: Math.min.apply(Math, yMins),
|
|
xMax: Math.max.apply(Math, xMaxs),
|
|
yMax: Math.max.apply(Math, yMaxs)
|
|
};
|
|
}
|
|
if (includeStroke) {
|
|
this.strokeBbox = bbox;
|
|
} else {
|
|
this.bbox = bbox;
|
|
}
|
|
return bbox;
|
|
}
|
|
};
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
beginFill: def.beginFill,
|
|
beginGradientFill: def.beginGradientFill,
|
|
beginBitmapFill: def.beginBitmapFill,
|
|
beginFillObject: def.beginFillObject,
|
|
beginStrokeObject: def.beginStrokeObject,
|
|
clear: def.clear,
|
|
copyFrom: def.copyFrom,
|
|
cubicCurveTo: def.cubicCurveTo,
|
|
curveTo: def.curveTo,
|
|
drawCircle: def.drawCircle,
|
|
drawEllipse: def.drawEllipse,
|
|
drawPath: def.drawPath,
|
|
drawRect: def.drawRect,
|
|
drawRoundRect: def.drawRoundRect,
|
|
drawRoundRectComplex: def.drawRoundRectComplex,
|
|
drawTriangles: def.drawTriangles,
|
|
endFill: def.endFill,
|
|
lineBitmapStyle: def.lineBitmapStyle,
|
|
lineGradientStyle: def.lineGradientStyle,
|
|
lineStyle: def.lineStyle,
|
|
moveTo: def.moveTo,
|
|
lineTo: def.lineTo
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
function createPatternStyle(bitmap, matrix, repeat, smooth) {
|
|
var repeatStyle = repeat === false ? 'no-repeat' : 'repeat';
|
|
var pattern = factoryCtx.createPattern(bitmap._drawable, repeatStyle);
|
|
var transform = matrix ? {
|
|
a: matrix.a,
|
|
b: matrix.b,
|
|
c: matrix.c,
|
|
d: matrix.d,
|
|
e: matrix.tx,
|
|
f: matrix.ty
|
|
} : {
|
|
a: 1,
|
|
b: 0,
|
|
c: 0,
|
|
d: 1,
|
|
e: 0,
|
|
f: 0
|
|
};
|
|
return {
|
|
style: pattern,
|
|
transform: transform,
|
|
smooth: smooth
|
|
};
|
|
}
|
|
function createGradientStyle(type, colors, alphas, ratios, matrix, spreadMethod, interpolationMethod, focalPos) {
|
|
type === null || type === undefined && throwError('TypeError', Errors.NullPointerError, 'type');
|
|
colors === null || type === undefined && throwError('TypeError', Errors.NullPointerError, 'colors');
|
|
if (!(type === 'linear' || type === 'radial')) {
|
|
throwError('ArgumentError', Errors.InvalidEnumError, 'type');
|
|
}
|
|
var colorStops = [];
|
|
for (var i = 0, n = colors.length; i < n; i++) {
|
|
colorStops.push({
|
|
ratio: ratios[i] / 255,
|
|
color: rgbIntAlphaToStr(colors[i], alphas[i])
|
|
});
|
|
}
|
|
var gradientConstructor;
|
|
if (type === 'linear') {
|
|
gradientConstructor = buildLinearGradientFactory(colorStops);
|
|
} else {
|
|
gradientConstructor = buildRadialGradientFactory(focalPos || 0, colorStops);
|
|
}
|
|
var scale = 819.2;
|
|
var transform = matrix ? {
|
|
a: scale * matrix.a,
|
|
b: scale * matrix.b,
|
|
c: scale * matrix.c,
|
|
d: scale * matrix.d,
|
|
e: matrix.tx,
|
|
f: matrix.ty
|
|
} : {
|
|
a: scale,
|
|
b: 0,
|
|
c: 0,
|
|
d: scale,
|
|
e: 0,
|
|
f: 0
|
|
};
|
|
return {
|
|
style: gradientConstructor,
|
|
transform: transform
|
|
};
|
|
}
|
|
function drawGraphicsData(data) {
|
|
if (data === null) {
|
|
return;
|
|
}
|
|
for (var i = 0; i < data.length; i++) {
|
|
var item = data[i];
|
|
if (flash.display.IGraphicsPath.class.isInstanceOf(item)) {
|
|
this._drawPathObject(item);
|
|
} else if (flash.display.IGraphicsStroke.class.isInstanceOf(item)) {
|
|
this.beginStrokeObject(item);
|
|
} else if (flash.display.IGraphicsFill.class.isInstanceOf(item)) {
|
|
this.beginFillObject(item);
|
|
}
|
|
}
|
|
}
|
|
var InteractiveObjectDefinition = function () {
|
|
var def = {
|
|
initialize: function () {
|
|
this._contextMenu = null;
|
|
this._doubleClickEnabled = false;
|
|
this._focusRect = null;
|
|
this._mouseEnabled = true;
|
|
this._tabEnabled = false;
|
|
},
|
|
get accessibilityImplementation() {
|
|
return null;
|
|
},
|
|
set accessibilityImplementation(val) {
|
|
somewhatImplemented('accessibilityImplementation');
|
|
},
|
|
get contextMenu() {
|
|
somewhatImplemented('contextMenu');
|
|
return this._contextMenu;
|
|
},
|
|
set contextMenu(val) {
|
|
somewhatImplemented('contextMenu');
|
|
this._contextMenu = val;
|
|
},
|
|
get doubleClickEnabled() {
|
|
return this._doubleClickEnabled;
|
|
},
|
|
set doubleClickEnabled(val) {
|
|
this._doubleClickEnabled = val;
|
|
},
|
|
get focusRect() {
|
|
return this._focusRect;
|
|
},
|
|
set focusRect(val) {
|
|
this._focusRect = val;
|
|
},
|
|
get mouseEnabled() {
|
|
return this._mouseEnabled;
|
|
},
|
|
set mouseEnabled(val) {
|
|
this._mouseEnabled = val;
|
|
},
|
|
get needsSoftKeyboard() {
|
|
return false;
|
|
},
|
|
set needsSoftKeyboard(val) {
|
|
notImplemented();
|
|
},
|
|
get softKeyboardInputAreaOfInterest() {
|
|
return null;
|
|
},
|
|
set softKeyboardInputAreaOfInterest(val) {
|
|
notImplemented();
|
|
},
|
|
get tabEnabled() {
|
|
return this._tabEnabled;
|
|
},
|
|
set tabEnabled(val) {
|
|
var old = this._tabEnabled;
|
|
this._tabEnabled = val;
|
|
if (old !== val) {
|
|
var Event = flash.events.Event;
|
|
this._dispatchEvent(new Event('tabEnabledChange', false, false));
|
|
}
|
|
},
|
|
requestSoftKeyboard: function () {
|
|
notImplemented();
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
tabEnabled: desc(def, 'tabEnabled'),
|
|
tabIndex: {
|
|
get: function tabIndex() {
|
|
return this._tabIndex;
|
|
},
|
|
set: function tabIndex(index) {
|
|
this._tabIndex = index;
|
|
}
|
|
},
|
|
focusRect: desc(def, 'focusRect'),
|
|
mouseEnabled: desc(def, 'mouseEnabled'),
|
|
doubleClickEnabled: desc(def, 'doubleClickEnabled'),
|
|
accessibilityImplementation: desc(def, 'accessibilityImplementation'),
|
|
softKeyboardInputAreaOfInterest: desc(def, 'softKeyboardInputAreaOfInterest'),
|
|
needsSoftKeyboard: desc(def, 'needsSoftKeyboard'),
|
|
contextMenu: desc(def, 'contextMenu'),
|
|
requestSoftKeyboard: def.requestSoftKeyboard
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var $RELEASE = false;
|
|
var LoaderDefinition = function () {
|
|
var WORKERS_ENABLED = true;
|
|
var LOADER_PATH = true ? 'shumway-worker.js' : 'swf/resourceloader.js';
|
|
var head = document.head;
|
|
head.insertBefore(document.createElement('style'), head.firstChild);
|
|
var style = document.styleSheets[0];
|
|
var def = {
|
|
__class__: 'flash.display.Loader',
|
|
initialize: function () {
|
|
this._contentLoaderInfo = new flash.display.LoaderInfo();
|
|
this._contentLoaderInfo._loader = this;
|
|
this._dictionary = {};
|
|
this._dictionaryResolved = {};
|
|
this._displayList = null;
|
|
this._timeline = [];
|
|
this._lastPromise = null;
|
|
this._uncaughtErrorEvents = null;
|
|
this._worker = null;
|
|
var abc = AVM2.currentAbc();
|
|
if (abc && abc.env.loader) {
|
|
this._contentLoaderInfo._loaderURL = abc.env.loader._contentLoaderInfo._url;
|
|
}
|
|
},
|
|
_commitData: function (data) {
|
|
switch (data.command) {
|
|
case 'init':
|
|
this._init(data.result);
|
|
break;
|
|
case 'progress':
|
|
this._updateProgress(data.result);
|
|
break;
|
|
case 'complete':
|
|
var frameConstructed = new Promise(function (resolve) {
|
|
avm2.systemDomain.onMessage.register('frameConstructed', function waitForFrame(type) {
|
|
if (type === 'frameConstructed') {
|
|
resolve();
|
|
avm2.systemDomain.onMessage.unregister('frameConstructed', waitForFrame);
|
|
}
|
|
});
|
|
});
|
|
this._contentLoaderInfo._dispatchEvent('parsed');
|
|
Promise.all([
|
|
frameConstructed,
|
|
this._lastPromise
|
|
]).then(function () {
|
|
this._content._complete = true;
|
|
this._contentLoaderInfo._dispatchEvent('complete');
|
|
}.bind(this));
|
|
var stats = data.stats;
|
|
if (stats) {
|
|
TelemetryService.reportTelemetry(stats);
|
|
}
|
|
this._worker && this._worker.terminate();
|
|
break;
|
|
case 'empty':
|
|
this._lastPromise = Promise.resolve();
|
|
break;
|
|
case 'error':
|
|
this._contentLoaderInfo._dispatchEvent('ioError', flash.events.IOErrorEvent);
|
|
break;
|
|
default:
|
|
if (data.id === 0)
|
|
break;
|
|
if (data.isSymbol)
|
|
this._commitSymbol(data);
|
|
else if (data.type === 'frame')
|
|
this._commitFrame(data);
|
|
else if (data.type === 'image')
|
|
this._commitImage(data);
|
|
break;
|
|
}
|
|
},
|
|
_updateProgress: function (state) {
|
|
var loaderInfo = this._contentLoaderInfo;
|
|
loaderInfo._bytesLoaded = state.bytesLoaded || 0;
|
|
loaderInfo._bytesTotal = state.bytesTotal || 0;
|
|
var event = new flash.events.ProgressEvent('progress', false, false, loaderInfo._bytesLoaded, loaderInfo._bytesTotal);
|
|
loaderInfo._dispatchEvent(event);
|
|
},
|
|
_buildFrame: function (currentDisplayList, timeline, promiseQueue, frame, frameNum) {
|
|
var loader = this;
|
|
var dictionary = loader._dictionary;
|
|
var dictionaryResolved = loader._dictionaryResolved;
|
|
var displayList = {};
|
|
var depths = [];
|
|
var cmds = frame.depths;
|
|
if (currentDisplayList) {
|
|
var currentDepths = currentDisplayList.depths;
|
|
for (var i = 0; i < currentDepths.length; i++) {
|
|
var depth = currentDepths[i];
|
|
if (cmds[depth] === null) {
|
|
continue;
|
|
}
|
|
displayList[depth] = currentDisplayList[depth];
|
|
depths.push(depth);
|
|
}
|
|
}
|
|
for (var depth in cmds) {
|
|
var cmd = cmds[depth];
|
|
if (!cmd) {
|
|
continue;
|
|
}
|
|
if (cmd.move) {
|
|
var oldCmd = cmd;
|
|
cmd = cloneObject(currentDisplayList[depth]);
|
|
for (var prop in oldCmd) {
|
|
var val = oldCmd[prop];
|
|
if (val) {
|
|
cmd[prop] = val;
|
|
}
|
|
}
|
|
}
|
|
if (cmd.symbolId) {
|
|
var itemPromise = dictionary[cmd.symbolId];
|
|
if (itemPromise && !dictionaryResolved[cmd.symbolId]) {
|
|
promiseQueue.push(itemPromise);
|
|
}
|
|
cmd = cloneObject(cmd);
|
|
Object.defineProperty(cmd, 'symbolInfo', {
|
|
get: function (dictionaryResolved, symbolId) {
|
|
return function () {
|
|
return dictionaryResolved[symbolId];
|
|
};
|
|
}(dictionaryResolved, cmd.symbolId)
|
|
});
|
|
}
|
|
if (!displayList[depth]) {
|
|
depths.push(depth);
|
|
}
|
|
displayList[depth] = cmd;
|
|
}
|
|
depths.sort(sortNumeric);
|
|
displayList.depths = depths;
|
|
var i = frame.repeat;
|
|
while (i--) {
|
|
timeline.push(displayList);
|
|
}
|
|
return displayList;
|
|
},
|
|
_commitFrame: function (frame) {
|
|
var abcBlocks = frame.abcBlocks;
|
|
var actionBlocks = frame.actionBlocks;
|
|
var initActionBlocks = frame.initActionBlocks;
|
|
var exports = frame.exports;
|
|
var symbolClasses = frame.symbolClasses;
|
|
var sceneData = frame.sceneData;
|
|
var loader = this;
|
|
var dictionary = loader._dictionary;
|
|
var loaderInfo = loader._contentLoaderInfo;
|
|
var timeline = loader._timeline;
|
|
var frameNum = timeline.length + 1;
|
|
var framePromiseResolve;
|
|
var framePromise = new Promise(function (resolve) {
|
|
framePromiseResolve = resolve;
|
|
});
|
|
var labelName = frame.labelName;
|
|
var prevPromise = this._lastPromise;
|
|
this._lastPromise = framePromise;
|
|
var promiseQueue = [
|
|
prevPromise
|
|
];
|
|
this._displayList = this._buildFrame(this._displayList, timeline, promiseQueue, frame, frameNum);
|
|
var framesLoaded = timeline.length;
|
|
if (frame.bgcolor)
|
|
loaderInfo._backgroundColor = frame.bgcolor;
|
|
else if (isNullOrUndefined(loaderInfo._backgroundColor))
|
|
loaderInfo._backgroundColor = {
|
|
red: 255,
|
|
green: 255,
|
|
blue: 255,
|
|
alpha: 255
|
|
};
|
|
Promise.all(promiseQueue).then(function () {
|
|
if (abcBlocks && loader._isAvm2Enabled) {
|
|
var appDomain = avm2.applicationDomain;
|
|
for (var i = 0, n = abcBlocks.length; i < n; i++) {
|
|
var abc = new AbcFile(abcBlocks[i].data, 'abc_block_' + i);
|
|
abc.env.loader = loader;
|
|
if (abcBlocks[i].flags) {
|
|
appDomain.loadAbc(abc);
|
|
} else {
|
|
appDomain.executeAbc(abc);
|
|
}
|
|
}
|
|
}
|
|
if (symbolClasses && loader._isAvm2Enabled) {
|
|
var symbolClassesPromises = [];
|
|
for (var i = 0, n = symbolClasses.length; i < n; i++) {
|
|
var asset = symbolClasses[i];
|
|
var symbolPromise = dictionary[asset.symbolId];
|
|
if (!symbolPromise)
|
|
continue;
|
|
symbolPromise.then(function (className) {
|
|
return function symbolPromiseResolved(symbolInfo) {
|
|
symbolInfo.className = className;
|
|
avm2.applicationDomain.getClass(className).setSymbol(symbolInfo.props);
|
|
};
|
|
}(asset.className));
|
|
symbolClassesPromises.push(symbolPromise);
|
|
}
|
|
return Promise.all(symbolClassesPromises);
|
|
}
|
|
if (exports && !loader._isAvm2Enabled) {
|
|
var exportPromises = [];
|
|
for (var i = 0, n = exports.length; i < n; i++) {
|
|
var asset = exports[i];
|
|
var symbolPromise = dictionary[asset.symbolId];
|
|
if (!symbolPromise)
|
|
continue;
|
|
symbolPromise.then(function (className) {
|
|
return function symbolPromiseResolved(symbolInfo) {
|
|
loader._avm1Context.addAsset(className, symbolInfo.props);
|
|
};
|
|
}(asset.className));
|
|
exportPromises.push(symbolPromise);
|
|
}
|
|
return Promise.all(exportPromises);
|
|
}
|
|
}).then(function () {
|
|
var root = loader._content;
|
|
var labelMap;
|
|
if (!root) {
|
|
var parent = loader._parent;
|
|
true;
|
|
var rootInfo = loader._dictionaryResolved[0];
|
|
var rootClass = avm2.applicationDomain.getClass(rootInfo.className);
|
|
root = rootClass.createAsSymbol({
|
|
framesLoaded: framesLoaded,
|
|
loader: loader,
|
|
parent: parent || loader,
|
|
index: parent ? 0 : -1,
|
|
level: parent ? 0 : -1,
|
|
timeline: timeline,
|
|
totalFrames: rootInfo.props.totalFrames,
|
|
stage: loader._stage,
|
|
complete: frame.complete
|
|
});
|
|
if (!loader._isAvm2Enabled) {
|
|
var avm1Context = loader._avm1Context;
|
|
var _root = root;
|
|
if (parent && parent !== loader._stage) {
|
|
var parentLoader = parent.loaderInfo._loader;
|
|
while (parentLoader._parent && parentLoader._parent !== loader._stage) {
|
|
parentLoader = parentLoader._parent.loaderInfo._loader;
|
|
}
|
|
if (parentLoader._isAvm2Enabled) {
|
|
somewhatImplemented('AVM1Movie');
|
|
this._worker && this._worker.terminate();
|
|
return;
|
|
}
|
|
_root = parentLoader._content;
|
|
}
|
|
var as2Object = _root._getAS2Object();
|
|
avm1Context.globals.asSetPublicProperty('_root', as2Object);
|
|
avm1Context.globals.asSetPublicProperty('_level0', as2Object);
|
|
avm1Context.globals.asSetPublicProperty('_level1', as2Object);
|
|
var parameters = loader.loaderInfo._parameters;
|
|
for (var paramName in parameters) {
|
|
if (!(paramName in as2Object)) {
|
|
as2Object[paramName] = parameters[paramName];
|
|
}
|
|
}
|
|
}
|
|
var isRootMovie = parent && parent == loader._stage && loader._stage._children.length === 0;
|
|
if (isRootMovie) {
|
|
parent._frameRate = loaderInfo._frameRate;
|
|
parent._stageHeight = loaderInfo._height;
|
|
parent._stageWidth = loaderInfo._width;
|
|
parent._root = root;
|
|
parent._setup();
|
|
} else {
|
|
loader._children.push(root);
|
|
}
|
|
var labels;
|
|
labelMap = root.symbol.labelMap = createEmptyObject();
|
|
if (sceneData) {
|
|
var scenes = [];
|
|
var startFrame;
|
|
var endFrame = root.symbol.totalFrames - 1;
|
|
var sd = sceneData.scenes;
|
|
var ld = sceneData.labels;
|
|
var i = sd.length;
|
|
while (i--) {
|
|
var s = sd[i];
|
|
startFrame = s.offset;
|
|
labels = [];
|
|
var j = ld.length;
|
|
while (j--) {
|
|
var lbl = ld[j];
|
|
if (lbl.frame >= startFrame && lbl.frame <= endFrame) {
|
|
labelMap[lbl.name] = lbl.frame + 1;
|
|
labels.unshift(new flash.display.FrameLabel(lbl.name, lbl.frame - startFrame + 1));
|
|
}
|
|
}
|
|
var scene = new flash.display.Scene(s.name, labels, endFrame - startFrame + 1);
|
|
scene._startFrame = startFrame + 1;
|
|
scene._endFrame = endFrame + 1;
|
|
scenes.unshift(scene);
|
|
endFrame = startFrame - 1;
|
|
}
|
|
root.symbol.scenes = scenes;
|
|
} else {
|
|
labels = [];
|
|
if (labelName) {
|
|
labelMap[labelName] = frameNum;
|
|
labels.push(new flash.display.FrameLabel(labelName, frameNum));
|
|
}
|
|
var scene = new flash.display.Scene('Scene 1', labels, root.symbol.totalFrames);
|
|
scene._startFrame = 1;
|
|
scene._endFrame = root.symbol.totalFrames;
|
|
root.symbol.scenes = [
|
|
scene
|
|
];
|
|
}
|
|
if (loader._stage) {
|
|
loader._stage._children[0] = root;
|
|
}
|
|
rootClass.instanceConstructor.call(root);
|
|
loader._content = root;
|
|
} else {
|
|
root._framesLoaded = framesLoaded;
|
|
if (labelName && root._labelMap) {
|
|
if (root._labelMap[labelName] === undefined) {
|
|
root._labelMap[labelName] = frameNum;
|
|
for (var i = 0, n = root.symbol.scenes.length; i < n; i++) {
|
|
var scene = root.symbol.scenes[i];
|
|
if (frameNum >= scene._startFrame && frameNum <= scene._endFrame) {
|
|
scene.labels.push(new flash.display.FrameLabel(labelName, frameNum - scene._startFrame));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (frame.startSounds) {
|
|
root._registerStartSounds(frameNum, frame.startSounds);
|
|
}
|
|
if (frame.soundStream) {
|
|
root._initSoundStream(frame.soundStream);
|
|
}
|
|
if (frame.soundStreamBlock) {
|
|
root._addSoundStreamBlock(frameNum, frame.soundStreamBlock);
|
|
}
|
|
if (!loader._isAvm2Enabled) {
|
|
var avm1Context = loader._avm1Context;
|
|
if (initActionBlocks) {
|
|
for (var i = 0; i < initActionBlocks.length; i++) {
|
|
var spriteId = initActionBlocks[i].spriteId;
|
|
var actionsData = initActionBlocks[i].actionsData;
|
|
root.addFrameScript(frameNum - 1, function (actionsData, spriteId, state) {
|
|
if (state.executed)
|
|
return;
|
|
state.executed = true;
|
|
return executeActions(actionsData, avm1Context, this._getAS2Object());
|
|
}.bind(root, actionsData, spriteId, {
|
|
executed: false
|
|
}));
|
|
}
|
|
}
|
|
if (actionBlocks) {
|
|
for (var i = 0; i < actionBlocks.length; i++) {
|
|
var block = actionBlocks[i];
|
|
root.addFrameScript(frameNum - 1, function (block) {
|
|
return function () {
|
|
return executeActions(block, avm1Context, this._getAS2Object());
|
|
};
|
|
}(block));
|
|
}
|
|
}
|
|
}
|
|
if (frameNum === 1)
|
|
loaderInfo._dispatchEvent(new flash.events.Event('init', false, false));
|
|
framePromiseResolve(frame);
|
|
});
|
|
},
|
|
_commitImage: function (imageInfo) {
|
|
var loader = this;
|
|
var imgPromiseResolve;
|
|
var imgPromise = this._lastPromise = new Promise(function (resolve) {
|
|
imgPromiseResolve = resolve;
|
|
});
|
|
var img = new Image();
|
|
imageInfo.props.img = img;
|
|
img.onload = function () {
|
|
var Bitmap = avm2.systemDomain.getClass('flash.display.Bitmap');
|
|
var BitmapData = avm2.systemDomain.getClass('flash.display.BitmapData');
|
|
var props = imageInfo.props;
|
|
props.parent = loader._parent;
|
|
props.stage = loader._stage;
|
|
props.skipCopyToCanvas = true;
|
|
var bitmapData = BitmapData.createAsSymbol(props);
|
|
BitmapData.instanceConstructor.call(bitmapData, 0, 0, true, 4294967295);
|
|
var image = Bitmap.createAsSymbol(bitmapData);
|
|
Bitmap.instanceConstructor.call(image, bitmapData);
|
|
image._parent = loader;
|
|
loader._children.push(image);
|
|
loader._invalidateBounds();
|
|
loader._content = image;
|
|
imgPromiseResolve(imageInfo);
|
|
var loaderInfo = loader._contentLoaderInfo;
|
|
loaderInfo._width = image.width;
|
|
loaderInfo._height = image.height;
|
|
loaderInfo._dispatchEvent('init');
|
|
};
|
|
img.src = URL.createObjectURL(imageInfo.data);
|
|
imageInfo.data = null;
|
|
},
|
|
_commitSymbol: function (symbol) {
|
|
var dictionary = this._dictionary;
|
|
var dictionaryResolved = this._dictionaryResolved;
|
|
if ('updates' in symbol) {
|
|
dictionary[symbol.id].then(function (s) {
|
|
for (var i in symbol.updates) {
|
|
s.props[i] = symbol.updates[i];
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
var className = 'flash.display.DisplayObject';
|
|
var dependencies = symbol.require;
|
|
var promiseQueue = [];
|
|
var props = {
|
|
symbolId: symbol.id,
|
|
loader: this
|
|
};
|
|
var symbolPromiseResolve;
|
|
var symbolPromise = new Promise(function (resolve) {
|
|
symbolPromiseResolve = resolve;
|
|
});
|
|
if (dependencies && dependencies.length) {
|
|
for (var i = 0, n = dependencies.length; i < n; i++) {
|
|
var dependencyId = dependencies[i];
|
|
var dependencyPromise = dictionary[dependencyId];
|
|
if (dependencyPromise && !dictionaryResolved[dependencyId])
|
|
promiseQueue.push(dependencyPromise);
|
|
}
|
|
}
|
|
switch (symbol.type) {
|
|
case 'button':
|
|
var states = {};
|
|
for (var stateName in symbol.states) {
|
|
var characters = [];
|
|
var displayList = {};
|
|
var state = symbol.states[stateName];
|
|
var depths = Object.keys(state);
|
|
for (var i = 0; i < depths.length; i++) {
|
|
var depth = depths[i];
|
|
var cmd = state[depth];
|
|
var characterPromise = dictionary[cmd.symbolId];
|
|
if (characterPromise && !dictionaryResolved[cmd.symbolId]) {
|
|
promiseQueue.push(characterPromise);
|
|
}
|
|
characters.push(characterPromise);
|
|
displayList[depth] = Object.create(cmd, {
|
|
symbolInfo: {
|
|
get: function (dictionaryResolved, symbolId) {
|
|
return function () {
|
|
return dictionaryResolved[symbolId];
|
|
};
|
|
}(dictionaryResolved, cmd.symbolId)
|
|
}
|
|
});
|
|
}
|
|
depths.sort(sortNumeric);
|
|
displayList.depths = depths;
|
|
states[stateName] = {
|
|
className: 'flash.display.Sprite',
|
|
props: {
|
|
loader: this,
|
|
timeline: [
|
|
displayList
|
|
]
|
|
}
|
|
};
|
|
}
|
|
className = 'flash.display.SimpleButton';
|
|
props.states = states;
|
|
props.buttonActions = symbol.buttonActions;
|
|
break;
|
|
case 'font':
|
|
var charset = fromCharCode.apply(null, symbol.codes);
|
|
if (charset) {
|
|
style.insertRule('@font-face{font-family:"' + symbol.uniqueName + '";' + 'src:url(data:font/opentype;base64,' + btoa(symbol.data) + ')' + '}', style.cssRules.length);
|
|
if (!/Mozilla\/5.0.*?rv:(\d+).*? Gecko/.test(window.navigator.userAgent)) {
|
|
var testDiv = document.createElement('div');
|
|
testDiv.setAttribute('style', 'position: absolute; top: 0; right: 0;visibility: hidden; z-index: -500;font-family:"' + symbol.uniqueName + '";');
|
|
testDiv.textContent = 'font test';
|
|
document.body.appendChild(testDiv);
|
|
var fontPromise = new Promise(function (resolve) {
|
|
setTimeout(function () {
|
|
resolve();
|
|
document.body.removeChild(testDiv);
|
|
}, 200);
|
|
});
|
|
promiseQueue.push(fontPromise);
|
|
}
|
|
}
|
|
className = 'flash.text.Font';
|
|
props.name = symbol.name;
|
|
props.uniqueName = symbol.uniqueName;
|
|
props.charset = symbol.charset;
|
|
props.bold = symbol.bold;
|
|
props.italic = symbol.italic;
|
|
props.metrics = symbol.metrics;
|
|
this._registerFont(className, props);
|
|
break;
|
|
case 'image':
|
|
var img = new Image();
|
|
var imgPromiseResolve;
|
|
var imgPromise = new Promise(function (resolve) {
|
|
imgPromiseResolve = resolve;
|
|
});
|
|
img.onload = function () {
|
|
if (symbol.mask) {
|
|
var maskCanvas = document.createElement('canvas');
|
|
maskCanvas.width = symbol.width;
|
|
maskCanvas.height = symbol.height;
|
|
var maskContext = maskCanvas.getContext('2d');
|
|
maskContext.drawImage(img, 0, 0);
|
|
var maskImageData = maskContext.getImageData(0, 0, symbol.width, symbol.height);
|
|
var maskImageDataBytes = maskImageData.data;
|
|
var symbolMaskBytes = symbol.mask;
|
|
var length = maskImageData.width * maskImageData.height;
|
|
for (var i = 0, j = 3; i < length; i++, j += 4) {
|
|
maskImageDataBytes[j] = symbolMaskBytes[i];
|
|
}
|
|
maskContext.putImageData(maskImageData, 0, 0);
|
|
props.img = maskCanvas;
|
|
}
|
|
imgPromiseResolve();
|
|
};
|
|
img.src = URL.createObjectURL(symbol.data);
|
|
promiseQueue.push(imgPromise);
|
|
className = 'flash.display.Bitmap';
|
|
props.img = img;
|
|
props.width = symbol.width;
|
|
props.height = symbol.height;
|
|
break;
|
|
case 'label':
|
|
var drawFn = new Function('c,r,ct', symbol.data);
|
|
className = 'flash.text.StaticText';
|
|
props.bbox = symbol.bbox;
|
|
props.draw = drawFn;
|
|
break;
|
|
case 'text':
|
|
props.bbox = symbol.bbox;
|
|
props.html = symbol.html;
|
|
if (symbol.type === 'label') {
|
|
className = 'flash.text.StaticText';
|
|
} else {
|
|
className = 'flash.text.TextField';
|
|
props.tag = symbol.tag;
|
|
props.variableName = symbol.variableName;
|
|
}
|
|
break;
|
|
case 'shape':
|
|
className = symbol.morph ? 'flash.display.MorphShape' : 'flash.display.Shape';
|
|
props.bbox = symbol.bbox;
|
|
props.strokeBbox = symbol.strokeBbox;
|
|
props.paths = symbol.paths;
|
|
props.dictionaryResolved = dictionaryResolved;
|
|
break;
|
|
case 'sound':
|
|
if (!symbol.pcm && !PLAY_USING_AUDIO_TAG) {
|
|
var decodePromiseResolve;
|
|
var decodePromise = new Promise(function (resolve) {
|
|
decodePromiseResolve = resolve;
|
|
});
|
|
MP3DecoderSession.processAll(symbol.packaged.data, function (props, pcm, id3tags, error) {
|
|
props.pcm = pcm || new Uint8Array(0);
|
|
decodePromiseResolve();
|
|
if (error) {
|
|
console.error('ERROR: ' + error);
|
|
}
|
|
}.bind(null, props));
|
|
promiseQueue.push(decodePromise);
|
|
}
|
|
className = 'flash.media.Sound';
|
|
props.sampleRate = symbol.sampleRate;
|
|
props.channels = symbol.channels;
|
|
props.pcm = symbol.pcm;
|
|
props.packaged = symbol.packaged;
|
|
break;
|
|
case 'binary':
|
|
props.data = symbol.data;
|
|
break;
|
|
case 'sprite':
|
|
var displayList = null;
|
|
var frameCount = symbol.frameCount;
|
|
var labelMap = {};
|
|
var frameNum = 1;
|
|
var frames = symbol.frames;
|
|
var timeline = [];
|
|
var startSoundRegistrations = [];
|
|
for (var i = 0, n = frames.length; i < n; i++) {
|
|
var frame = frames[i];
|
|
var frameNum = timeline.length + 1;
|
|
if (frame.labelName) {
|
|
labelMap[frame.labelName] = frameNum;
|
|
}
|
|
if (frame.startSounds) {
|
|
startSoundRegistrations[frameNum] = frame.startSounds;
|
|
for (var j = 0; j < frame.startSounds.length; j++) {
|
|
var soundId = frame.startSounds[j].soundId;
|
|
var itemPromise = dictionary[soundId];
|
|
if (itemPromise && !dictionaryResolved[soundId]) {
|
|
promiseQueue.push(itemPromise);
|
|
}
|
|
}
|
|
}
|
|
displayList = this._buildFrame(displayList, timeline, promiseQueue, frame, frameNum);
|
|
}
|
|
var frameScripts = {};
|
|
if (!this._isAvm2Enabled) {
|
|
if (symbol.frameScripts) {
|
|
var data = symbol.frameScripts;
|
|
for (var i = 0; i < data.length; i += 2) {
|
|
var frameNum = data[i] + 1;
|
|
var block = data[i + 1];
|
|
var script = function (block, loader) {
|
|
return function () {
|
|
var avm1Context = loader._avm1Context;
|
|
return executeActions(block, avm1Context, this._getAS2Object());
|
|
};
|
|
}(block, this);
|
|
if (!frameScripts[frameNum])
|
|
frameScripts[frameNum] = [
|
|
script
|
|
];
|
|
else
|
|
frameScripts[frameNum].push(script);
|
|
}
|
|
}
|
|
}
|
|
className = 'flash.display.MovieClip';
|
|
props.timeline = timeline;
|
|
props.framesLoaded = frameCount;
|
|
props.labelMap = labelMap;
|
|
props.frameScripts = frameScripts;
|
|
props.totalFrames = frameCount;
|
|
props.startSoundRegistrations = startSoundRegistrations;
|
|
break;
|
|
}
|
|
dictionary[symbol.id] = symbolPromise;
|
|
Promise.all(promiseQueue).then(function () {
|
|
var symbolInfo = {
|
|
className: className,
|
|
props: props
|
|
};
|
|
dictionaryResolved[symbol.id] = symbolInfo;
|
|
symbolPromiseResolve(symbolInfo);
|
|
});
|
|
},
|
|
_registerFont: function (className, props) {
|
|
this._vmPromise.then(function () {
|
|
var fontClass = avm2.applicationDomain.getClass(className);
|
|
var font = fontClass.createAsSymbol(props);
|
|
fontClass.instanceConstructor.call(font);
|
|
});
|
|
},
|
|
_init: function (info) {
|
|
var loader = this;
|
|
var loaderInfo = loader._contentLoaderInfo;
|
|
loaderInfo._swfVersion = info.swfVersion;
|
|
var bbox = info.bbox;
|
|
loaderInfo._width = bbox.xMax - bbox.xMin;
|
|
loaderInfo._height = bbox.yMax - bbox.yMin;
|
|
loaderInfo._frameRate = info.frameRate;
|
|
var vmPromiseResolve, vmPromiseReject;
|
|
var vmPromise = new Promise(function (resolve, reject) {
|
|
vmPromiseResolve = resolve;
|
|
vmPromiseReject = reject;
|
|
});
|
|
vmPromise.resolve = vmPromiseResolve;
|
|
vmPromise.reject = vmPromiseReject;
|
|
var documentPromise = new Promise(function (resolve) {
|
|
vmPromise.then(function () {
|
|
var rootInfo = {
|
|
className: 'flash.display.MovieClip',
|
|
props: {
|
|
totalFrames: info.frameCount
|
|
}
|
|
};
|
|
loader._dictionaryResolved[0] = rootInfo;
|
|
resolve(rootInfo);
|
|
});
|
|
});
|
|
loader._dictionary[0] = documentPromise;
|
|
loader._lastPromise = documentPromise;
|
|
loader._vmPromise = vmPromise;
|
|
loader._isAvm2Enabled = info.fileAttributes.doAbc;
|
|
this._setup();
|
|
},
|
|
_load: function (request, checkPolicyFile, applicationDomain, securityDomain, requestedContentParent, parameters, deblockingFilter, allowCodeImport, imageDecodingPolicy) {
|
|
if (flash.net.URLRequest.class.isInstanceOf(request)) {
|
|
this._contentLoaderInfo._url = request._url;
|
|
}
|
|
var worker;
|
|
if (WORKERS_ENABLED) {
|
|
worker = new Worker(SHUMWAY_ROOT + LOADER_PATH);
|
|
} else {
|
|
worker = new ResourceLoader(window);
|
|
}
|
|
var loader = this;
|
|
loader._worker = worker;
|
|
worker.onmessage = function (evt) {
|
|
if (evt.data.type === 'exception') {
|
|
avm2.exceptions.push({
|
|
source: 'parser',
|
|
message: evt.data.message,
|
|
stack: evt.data.stack
|
|
});
|
|
} else {
|
|
loader._commitData(evt.data);
|
|
}
|
|
};
|
|
if (flash.net.URLRequest.class.isInstanceOf(request)) {
|
|
var session = FileLoadingService.createSession();
|
|
session.onprogress = function (data, progress) {
|
|
worker.postMessage({
|
|
data: data,
|
|
progress: progress
|
|
});
|
|
};
|
|
session.onerror = function (error) {
|
|
loader._commitData({
|
|
command: 'error',
|
|
error: error
|
|
});
|
|
};
|
|
session.onopen = function () {
|
|
worker.postMessage('pipe:');
|
|
};
|
|
session.onclose = function () {
|
|
worker.postMessage({
|
|
data: null
|
|
});
|
|
};
|
|
session.open(request._toFileRequest());
|
|
} else {
|
|
worker.postMessage(request);
|
|
}
|
|
},
|
|
_setup: function () {
|
|
var loader = this;
|
|
var stage = loader._stage;
|
|
if (loader._isAvm2Enabled) {
|
|
var mouseClass = avm2.systemDomain.getClass('flash.ui.Mouse');
|
|
mouseClass._stage = stage;
|
|
loader._vmPromise.resolve();
|
|
return;
|
|
}
|
|
if (!avm2.loadAVM1) {
|
|
loader._vmPromise.reject('AVM1 loader is not found');
|
|
return;
|
|
}
|
|
var loaded = function () {
|
|
var loaderInfo = loader._contentLoaderInfo;
|
|
var avm1Context = new AS2Context(loaderInfo._swfVersion);
|
|
avm1Context.stage = stage;
|
|
loader._avm1Context = avm1Context;
|
|
avm1lib.AS2Key.class.$bind(stage);
|
|
avm1lib.AS2Mouse.class.$bind(stage);
|
|
stage._addEventListener('frameConstructed', avm1Context.flushPendingScripts.bind(avm1Context), false, Number.MAX_VALUE);
|
|
loader._vmPromise.resolve();
|
|
};
|
|
if (avm2.isAVM1Loaded) {
|
|
if (AS2Context.instance) {
|
|
loader._avm1Context = AS2Context.instance;
|
|
loader._vmPromise.resolve();
|
|
} else {
|
|
loaded();
|
|
}
|
|
} else {
|
|
avm2.isAVM1Loaded = true;
|
|
avm2.loadAVM1(loaded);
|
|
}
|
|
},
|
|
get contentLoaderInfo() {
|
|
return this._contentLoaderInfo;
|
|
},
|
|
get content() {
|
|
somewhatImplemented('Loader.content');
|
|
return this._content;
|
|
}
|
|
};
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
content: Object.getOwnPropertyDescriptor(def, 'content'),
|
|
contentLoaderInfo: Object.getOwnPropertyDescriptor(def, 'contentLoaderInfo'),
|
|
_getJPEGLoaderContextdeblockingfilter: function (context) {
|
|
return 0;
|
|
},
|
|
_load: def._load,
|
|
_loadBytes: function _loadBytes(bytes, checkPolicyFile, applicationDomain, securityDomain, requestedContentParent, parameters, deblockingFilter, allowLoadBytesCodeExecution, imageDecodingPolicy) {
|
|
this._load(bytes.a, checkPolicyFile, applicationDomain, securityDomain, requestedContentParent, parameters, deblockingFilter, allowLoadBytesCodeExecution, imageDecodingPolicy);
|
|
},
|
|
_unload: function _unload(halt, gc) {
|
|
somewhatImplemented('Loader._unload, do we even need to do anything here?');
|
|
},
|
|
_close: function _close() {
|
|
somewhatImplemented('Loader._close');
|
|
},
|
|
_getUncaughtErrorEvents: function _getUncaughtErrorEvents() {
|
|
somewhatImplemented('Loader._getUncaughtErrorEvents');
|
|
return this._uncaughtErrorEvents;
|
|
},
|
|
_setUncaughtErrorEvents: function _setUncaughtErrorEvents(value) {
|
|
somewhatImplemented('Loader._setUncaughtErrorEvents');
|
|
this._uncaughtErrorEvents = value;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var LoaderInfoDefinition = function () {
|
|
function dispatchEvent(event) {
|
|
notImplemented('LoaderInfo.dispatchEvent');
|
|
}
|
|
return {
|
|
__class__: 'flash.display.LoaderInfo',
|
|
initialize: function () {
|
|
this._actionScriptVersion = null;
|
|
this._backgroundColor = null;
|
|
this._bytes = null;
|
|
this._bytesLoaded = 0;
|
|
this._bytesTotal = 0;
|
|
this._content = null;
|
|
this._contentType = null;
|
|
this._frameRate = null;
|
|
this._height = null;
|
|
this._loader = null;
|
|
this._loaderURL = null;
|
|
this._swfVersion = null;
|
|
this._url = null;
|
|
this._width = null;
|
|
this._uncaughtErrorEvents = null;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
getLoaderInfoByDefinition: function getLoaderInfoByDefinition(object) {
|
|
notImplemented('LoaderInfo.getLoaderInfoByDefinition');
|
|
}
|
|
},
|
|
instance: {
|
|
_getArgs: function _getArgs() {
|
|
var params = this._parameters;
|
|
var mangled = {};
|
|
for (var k in params) {
|
|
mangled[Multiname.getPublicQualifiedName(k)] = params[k];
|
|
}
|
|
return mangled;
|
|
},
|
|
_getUncaughtErrorEvents: function _getUncaughtErrorEvents() {
|
|
somewhatImplemented('Loader._getUncaughtErrorEvents');
|
|
return this._uncaughtErrorEvents;
|
|
},
|
|
_setUncaughtErrorEvents: function _setUncaughtErrorEvents(value) {
|
|
somewhatImplemented('Loader._setUncaughtErrorEvents');
|
|
this._uncaughtErrorEvents = value;
|
|
},
|
|
loaderURL: {
|
|
get: function loaderURL() {
|
|
return this._loaderURL;
|
|
}
|
|
},
|
|
url: {
|
|
get: function url() {
|
|
return this._url;
|
|
}
|
|
},
|
|
isURLInaccessible: {
|
|
get: function isURLInaccessible() {
|
|
return this._isURLInaccessible;
|
|
}
|
|
},
|
|
bytesLoaded: {
|
|
get: function bytesLoaded() {
|
|
return this._bytesLoaded;
|
|
}
|
|
},
|
|
bytesTotal: {
|
|
get: function bytesTotal() {
|
|
return this._bytesTotal;
|
|
}
|
|
},
|
|
applicationDomain: {
|
|
get: function applicationDomain() {
|
|
return new flash.system.ApplicationDomain(avm2.applicationDomain);
|
|
}
|
|
},
|
|
swfVersion: {
|
|
get: function swfVersion() {
|
|
return this._swfVersion;
|
|
}
|
|
},
|
|
actionScriptVersion: {
|
|
get: function actionScriptVersion() {
|
|
return this._actionScriptVersion;
|
|
}
|
|
},
|
|
frameRate: {
|
|
get: function frameRate() {
|
|
return this._frameRate;
|
|
}
|
|
},
|
|
width: {
|
|
get: function width() {
|
|
return this._width;
|
|
}
|
|
},
|
|
height: {
|
|
get: function height() {
|
|
return this._height;
|
|
}
|
|
},
|
|
contentType: {
|
|
get: function contentType() {
|
|
return this._contentType;
|
|
}
|
|
},
|
|
sharedEvents: {
|
|
get: function sharedEvents() {
|
|
return this._sharedEvents;
|
|
}
|
|
},
|
|
parentSandboxBridge: {
|
|
get: function parentSandboxBridge() {
|
|
return this._parentSandboxBridge;
|
|
},
|
|
set: function parentSandboxBridge(door) {
|
|
this._parentSandboxBridge = door;
|
|
}
|
|
},
|
|
childSandboxBridge: {
|
|
get: function childSandboxBridge() {
|
|
return this._childSandboxBridge;
|
|
},
|
|
set: function childSandboxBridge(door) {
|
|
this._childSandboxBridge = door;
|
|
}
|
|
},
|
|
sameDomain: {
|
|
get: function sameDomain() {
|
|
return this._sameDomain;
|
|
}
|
|
},
|
|
childAllowsParent: {
|
|
get: function childAllowsParent() {
|
|
return this._childAllowsParent;
|
|
}
|
|
},
|
|
parentAllowsChild: {
|
|
get: function parentAllowsChild() {
|
|
return this._parentAllowsChild;
|
|
}
|
|
},
|
|
loader: {
|
|
get: function loader() {
|
|
return this._loader;
|
|
}
|
|
},
|
|
content: {
|
|
get: function content() {
|
|
return this._loader._content;
|
|
}
|
|
},
|
|
bytes: {
|
|
get: function bytes() {
|
|
return this._bytes;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: scriptProperties('public', [
|
|
'swfVersion',
|
|
'bytesTotal',
|
|
'bytesLoaded',
|
|
'parameters',
|
|
'uncaughtErrorEvent'
|
|
])
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var MorphShapeDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.display.MorphShape',
|
|
initialize: function () {
|
|
var graphics = this._graphics = new flash.display.Graphics();
|
|
var s = this.symbol;
|
|
if (s && s.paths) {
|
|
graphics._paths = s.paths;
|
|
graphics.bbox = s.bbox;
|
|
graphics.strokeBbox = s.strokeBbox;
|
|
if (this._stage && this._stage._quality === 'low' && !graphics._bitmap)
|
|
graphics._cacheAsBitmap(this._bbox);
|
|
}
|
|
}
|
|
};
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
graphics: {
|
|
get: function () {
|
|
return this._graphics;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var MovieClipDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.display.MovieClip',
|
|
initialize: function () {
|
|
this._playHead = 1;
|
|
this._currentFrame = 1;
|
|
this._currentFrameLabel = null;
|
|
this._currentLabel = null;
|
|
this._currentScene = 0;
|
|
this._enabled = true;
|
|
this._frameScripts = {};
|
|
this._framesLoaded = 1;
|
|
this._isPlaying = false;
|
|
this._labelMap = {};
|
|
this._sceneFrameMap = {};
|
|
this._sceneMap = {};
|
|
this._scenes = null;
|
|
this._timeline = null;
|
|
this._totalFrames = 1;
|
|
this._startSoundRegistrations = [];
|
|
this._allowFrameNavigation = true;
|
|
this._complete = true;
|
|
var s = this.symbol;
|
|
if (s) {
|
|
this._timeline = s.timeline || null;
|
|
this._framesLoaded = s.framesLoaded || 1;
|
|
this._labelMap = Object.create(s.labelMap || null);
|
|
this._frameScripts = Object.create(s.frameScripts || null);
|
|
this._totalFrames = s.totalFrames || 1;
|
|
this._startSoundRegistrations = s.startSoundRegistrations || [];
|
|
this._scenes = s.scenes || null;
|
|
this._complete = s.complete === false ? false : true;
|
|
var map = this._labelMap;
|
|
for (var name in map) {
|
|
var frame = map[name];
|
|
if (frame == 1) {
|
|
this._currentFrameLabel = this._currentLabel = name;
|
|
}
|
|
}
|
|
}
|
|
this._enterFrame(1);
|
|
var self = this;
|
|
this._onExecuteFrame = function onExecuteFrame() {
|
|
self._removeEventListener('executeFrame', onExecuteFrame);
|
|
self._allowFrameNavigation = false;
|
|
self._callFrame(self._currentFrame);
|
|
self._allowFrameNavigation = true;
|
|
if (self._playHead !== self._currentFrame) {
|
|
self._gotoFrame(self._playHead, true);
|
|
}
|
|
self._postConstructChildren();
|
|
};
|
|
this._addEventListener('executeFrame', this._onExecuteFrame);
|
|
if (this._complete && this._totalFrames <= 1) {
|
|
return this;
|
|
}
|
|
this._onAdvanceFrame = function onAdvanceFrame() {
|
|
var frameNum = self._playHead + 1;
|
|
if (self._complete && frameNum > self._totalFrames) {
|
|
frameNum = 1;
|
|
} else if (frameNum > self._framesLoaded) {
|
|
return;
|
|
}
|
|
self._updateDisplayList(frameNum);
|
|
if (self._sparse) {
|
|
self._addEventListener('constructChildren', self._onConstructChildren);
|
|
}
|
|
self._startSounds(frameNum);
|
|
self._enterFrame(frameNum);
|
|
if (frameNum in self._frameScripts) {
|
|
self._addEventListener('executeFrame', self._onExecuteFrame);
|
|
}
|
|
};
|
|
this._onConstructChildren = function onConstructChildren() {
|
|
self._removeEventListener('constructChildren', onConstructChildren);
|
|
self._constructChildren();
|
|
};
|
|
this.play();
|
|
},
|
|
_updateDisplayList: function (nextFrameNum) {
|
|
this._destructChildren(nextFrameNum);
|
|
this._declareChildren(nextFrameNum);
|
|
},
|
|
_declareChildren: function declareChildren(nextFrameNum) {
|
|
var currentFrame = this._currentFrame;
|
|
if (nextFrameNum === currentFrame) {
|
|
return;
|
|
}
|
|
var timeline = this._timeline;
|
|
var nextDisplayList = timeline[nextFrameNum - 1];
|
|
if (nextDisplayList === timeline[currentFrame - 1]) {
|
|
return;
|
|
}
|
|
var prevDisplayListItem = null;
|
|
var currentDisplayListItem = this._currentDisplayList;
|
|
var children = this._children;
|
|
var depths = nextDisplayList.depths;
|
|
var index = children.length;
|
|
var i = depths.length;
|
|
while (i--) {
|
|
var depth = depths[i], depthInt = depth | 0;
|
|
while (currentDisplayListItem && currentDisplayListItem.depth > depthInt) {
|
|
prevDisplayListItem = currentDisplayListItem;
|
|
currentDisplayListItem = currentDisplayListItem.next;
|
|
}
|
|
var currentChild = null;
|
|
if (currentDisplayListItem && currentDisplayListItem.depth === depthInt) {
|
|
currentChild = currentDisplayListItem.obj;
|
|
if (currentChild && currentChild._owned) {
|
|
index = this.getChildIndex(currentChild);
|
|
}
|
|
}
|
|
var currentCmd = currentDisplayListItem && currentDisplayListItem.depth === depthInt ? currentDisplayListItem.cmd : null;
|
|
var nextCmd = nextDisplayList[depth];
|
|
if (!nextCmd || nextCmd === currentCmd) {
|
|
continue;
|
|
}
|
|
if (currentCmd && currentChild && nextCmd.symbolId === currentCmd.symbolId && nextCmd.ratio === currentCmd.ratio) {
|
|
if (currentChild._animated) {
|
|
currentChild._invalidate();
|
|
if (nextCmd.hasMatrix) {
|
|
currentChild._setTransformMatrix(nextCmd.matrix, false);
|
|
}
|
|
if (nextCmd.hasCxform) {
|
|
currentChild._cxform = nextCmd.cxform;
|
|
}
|
|
if (nextCmd.clip) {
|
|
currentChild._clipDepth = nextCmd.clipDepth;
|
|
}
|
|
if (nextCmd.hasName) {
|
|
currentChild.name = nextCmd.name;
|
|
}
|
|
if (nextCmd.blend) {
|
|
currentChild._blendMode = this._resolveBlendMode(nextCmd.blendMode);
|
|
}
|
|
}
|
|
currentDisplayListItem.cmd = nextCmd;
|
|
continue;
|
|
}
|
|
var newDisplayListItem = this._addTimelineChild(nextCmd, index);
|
|
newDisplayListItem.next = currentDisplayListItem;
|
|
if (prevDisplayListItem) {
|
|
prevDisplayListItem.next = newDisplayListItem;
|
|
} else {
|
|
this._currentDisplayList = newDisplayListItem;
|
|
}
|
|
prevDisplayListItem = newDisplayListItem;
|
|
}
|
|
},
|
|
_destructChildren: function destructChildren(nextFrameNum) {
|
|
var currentFrame = this._currentFrame;
|
|
if (nextFrameNum === currentFrame) {
|
|
return;
|
|
}
|
|
var timeline = this._timeline;
|
|
var nextDisplayList = timeline[nextFrameNum - 1];
|
|
if (nextDisplayList === timeline[currentFrame - 1]) {
|
|
return;
|
|
}
|
|
var prevEntry = null;
|
|
var currentEntry = this._currentDisplayList;
|
|
var toRemove = null;
|
|
while (currentEntry) {
|
|
var depth = currentEntry.depth;
|
|
var currentCmd = currentEntry.cmd;
|
|
var nextCmd = nextDisplayList[depth];
|
|
if (!nextCmd || nextCmd.symbolId !== currentCmd.symbolId || nextCmd.ratio !== currentCmd.ratio) {
|
|
var nextDisplayListItem = currentEntry.next;
|
|
if (prevEntry) {
|
|
prevEntry.next = nextDisplayListItem;
|
|
} else {
|
|
this._currentDisplayList = nextDisplayListItem;
|
|
}
|
|
currentEntry.next = toRemove;
|
|
toRemove = currentEntry;
|
|
currentEntry = nextDisplayListItem;
|
|
} else {
|
|
prevEntry = currentEntry;
|
|
currentEntry = currentEntry.next;
|
|
}
|
|
}
|
|
while (toRemove) {
|
|
var child = toRemove.obj;
|
|
if (child && child._owned) {
|
|
this._sparse = true;
|
|
this.removeChild(child);
|
|
child.destroy();
|
|
if (child._isPlaying) {
|
|
child.stop();
|
|
}
|
|
}
|
|
toRemove = toRemove.next;
|
|
}
|
|
},
|
|
_gotoFrame: function gotoFrame(frameNum, execute) {
|
|
var enterFrame = frameNum !== this._currentFrame;
|
|
if (this._allowFrameNavigation || !this._loader._isAvm2Enabled) {
|
|
if (enterFrame) {
|
|
this._updateDisplayList(frameNum);
|
|
this._enterFrame(frameNum);
|
|
}
|
|
this._constructChildren();
|
|
if (this._loader._isAvm2Enabled && this.loaderInfo._swfVersion >= 10) {
|
|
if (enterFrame) {
|
|
this._addEventListener('executeFrame', this._onExecuteFrame);
|
|
}
|
|
var domain = avm2.systemDomain;
|
|
domain.broadcastMessage('frameConstructed');
|
|
domain.broadcastMessage('executeFrame');
|
|
domain.broadcastMessage('exitFrame');
|
|
return;
|
|
}
|
|
if (enterFrame && (execute || !this._loader._isAvm2Enabled)) {
|
|
this._callFrame(frameNum);
|
|
}
|
|
this._postConstructChildren();
|
|
return;
|
|
}
|
|
if (enterFrame) {
|
|
this._playHead = frameNum;
|
|
}
|
|
},
|
|
_enterFrame: function navigate(frameNum) {
|
|
if (frameNum === this._currentFrame) {
|
|
return;
|
|
}
|
|
this._currentFrameLabel = null;
|
|
if (frameNum === 1) {
|
|
this._currentLabel = null;
|
|
}
|
|
var map = this._labelMap;
|
|
for (var name in map) {
|
|
if (map[name] === frameNum) {
|
|
this._currentFrameLabel = this._currentLabel = name;
|
|
break;
|
|
}
|
|
}
|
|
if (this._scenes) {
|
|
var scenes = this._scenes;
|
|
for (var j = 0, n = scenes.length; j < n; j++) {
|
|
var scene = scenes[j];
|
|
if (frameNum >= scene._startFrame && frameNum <= scene._endFrame) {
|
|
this._currentScene = j;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
this._playHead = this._currentFrame = frameNum;
|
|
},
|
|
_callFrame: function callFrame(frame) {
|
|
if (isNaN(frame)) {
|
|
frame = this._labelMap[frame];
|
|
if (frame === undefined) {
|
|
return;
|
|
}
|
|
}
|
|
if (frame in this._frameScripts) {
|
|
var scripts = this._frameScripts[frame];
|
|
try {
|
|
for (var i = 0, n = scripts.length; i < n; i++) {
|
|
scripts[i].call(this);
|
|
}
|
|
} catch (e) {
|
|
var AVM2_ERROR_TYPE = 2;
|
|
TelemetryService.reportTelemetry({
|
|
topic: 'error',
|
|
error: AVM2_ERROR_TYPE
|
|
});
|
|
if (false) {
|
|
console.error('error ' + e + ', stack: \n' + e.stack);
|
|
}
|
|
this.stop();
|
|
throw e;
|
|
}
|
|
}
|
|
},
|
|
_gotoButtonState: function gotoButtonState(stateName) {
|
|
if (this._enabled) {
|
|
this.gotoLabel('_' + stateName);
|
|
}
|
|
},
|
|
_getAbsFrameNum: function (frameNum, sceneName) {
|
|
if (frameNum < 1) {
|
|
frameNum = 1;
|
|
}
|
|
if (sceneName && this._scenes && this._scenes.length > 1) {
|
|
var scenes = this._scenes;
|
|
for (var i = 0; i < scenes.length; i++) {
|
|
var scene = scenes[i];
|
|
if (scene.name === sceneName) {
|
|
frameNum += scene._startFrame - 1;
|
|
if (frameNum > scene._endFrame) {
|
|
frameNum = scene._endFrame;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (frameNum > this._framesLoaded) {
|
|
return this._framesLoaded;
|
|
}
|
|
return frameNum;
|
|
},
|
|
_registerStartSounds: function (frameNum, starts) {
|
|
this._startSoundRegistrations[frameNum] = starts;
|
|
},
|
|
_initSoundStream: function (streamInfo) {
|
|
this._soundStream = new MovieClipSoundStream(streamInfo, this);
|
|
},
|
|
_addSoundStreamBlock: function (frameNum, streamBlock) {
|
|
this._soundStream.appendBlock(frameNum, streamBlock);
|
|
},
|
|
_startSounds: function (frameNum) {
|
|
var starts = this._startSoundRegistrations[frameNum];
|
|
if (starts) {
|
|
var sounds = this._sounds || (this._sounds = {});
|
|
var loader = this.loaderInfo._loader;
|
|
for (var i = 0; i < starts.length; i++) {
|
|
var start = starts[i];
|
|
var symbolId = start.soundId;
|
|
var info = start.soundInfo;
|
|
var sound = sounds[symbolId];
|
|
if (!sound) {
|
|
var symbolInfo = loader._dictionaryResolved[symbolId];
|
|
if (!symbolInfo)
|
|
continue;
|
|
var symbolClass = avm2.systemDomain.findClass(symbolInfo.className) ? avm2.systemDomain.getClass(symbolInfo.className) : avm2.applicationDomain.getClass(symbolInfo.className);
|
|
var soundObj = symbolClass.createAsSymbol(symbolInfo.props);
|
|
symbolClass.instanceConstructor.call(soundObj);
|
|
sounds[symbolId] = sound = {
|
|
object: soundObj
|
|
};
|
|
}
|
|
if (sound.channel) {
|
|
sound.channel.stop();
|
|
sound.channel = null;
|
|
}
|
|
if (!info.stop) {
|
|
var loops = info.hasLoops ? info.loopCount : 0;
|
|
sound.channel = sound.object.play(0, loops);
|
|
}
|
|
}
|
|
}
|
|
if (this._soundStream) {
|
|
this._soundStream.playFrame(frameNum);
|
|
}
|
|
},
|
|
_getAS2Object: function () {
|
|
if (!this.$as2Object) {
|
|
if (this._avm1SymbolClass) {
|
|
var nativeObject = this, nativeObjectClass = this._avm1SymbolClass;
|
|
var constructWrapper = function () {
|
|
this.init(nativeObject);
|
|
nativeObjectClass.call(this);
|
|
};
|
|
constructWrapper.prototype = Object.create(nativeObjectClass.prototype);
|
|
constructWrapper.instanceConstructor = constructWrapper;
|
|
constructWrapper.debugName = 'avm1 <symbol constructor wrapper>';
|
|
construct(constructWrapper);
|
|
} else {
|
|
new avm1lib.AS2MovieClip(this);
|
|
}
|
|
}
|
|
return this.$as2Object;
|
|
},
|
|
get currentFrame() {
|
|
var frameNum = this._currentFrame;
|
|
return this._scenes ? frameNum - this.currentScene._startFrame + 1 : frameNum;
|
|
},
|
|
get currentFrameLabel() {
|
|
return this._currentFrameLabel;
|
|
},
|
|
get currentLabel() {
|
|
return this._currentLabel;
|
|
},
|
|
get currentLabels() {
|
|
if (this._scenes) {
|
|
return this._scenes[this._currentScene].labels;
|
|
} else {
|
|
var labels = [];
|
|
var map = this._labelMap;
|
|
for (var name in map) {
|
|
labels.push(new flash.display.FrameLabel(name, map[name]));
|
|
}
|
|
return labels;
|
|
}
|
|
},
|
|
get currentScene() {
|
|
return this._scenes ? this._scenes[this._currentScene] : new flash.display.Scene('', this.currentLabels, this._framesLoaded);
|
|
},
|
|
get enabled() {
|
|
return this._enabled;
|
|
},
|
|
set enabled(val) {
|
|
this._enabled = val;
|
|
},
|
|
get framesLoaded() {
|
|
return this._framesLoaded;
|
|
},
|
|
get totalFrames() {
|
|
return this._totalFrames;
|
|
},
|
|
get scenes() {
|
|
return this._scenes || [
|
|
new flash.display.Scene('', this.currentLabels, this._framesLoaded)
|
|
];
|
|
},
|
|
get trackAsMenu() {
|
|
return false;
|
|
},
|
|
set trackAsMenu(val) {
|
|
notImplemented();
|
|
},
|
|
addFrameScript: function () {
|
|
var frameScripts = this._frameScripts;
|
|
for (var i = 0, n = arguments.length; i < n; i += 2) {
|
|
var frameNum = arguments[i] + 1;
|
|
var fn = arguments[i + 1];
|
|
if (!fn) {
|
|
continue;
|
|
}
|
|
var scripts = frameScripts[frameNum];
|
|
if (scripts) {
|
|
scripts.push(fn);
|
|
} else {
|
|
frameScripts[frameNum] = [
|
|
fn
|
|
];
|
|
}
|
|
if (frameNum === this._currentFrame) {
|
|
this._addEventListener('executeFrame', this._onExecuteFrame);
|
|
}
|
|
}
|
|
},
|
|
gotoAndPlay: function (frame, scene) {
|
|
this.play();
|
|
if (isNaN(frame)) {
|
|
this.gotoLabel(frame);
|
|
} else {
|
|
this._gotoFrame(this._getAbsFrameNum(frame, scene));
|
|
}
|
|
},
|
|
gotoAndStop: function (frame, scene) {
|
|
this.stop();
|
|
if (isNaN(frame)) {
|
|
this.gotoLabel(frame);
|
|
} else {
|
|
this._gotoFrame(this._getAbsFrameNum(frame, scene));
|
|
}
|
|
},
|
|
gotoLabel: function (labelName) {
|
|
var frameNum = this._labelMap[labelName];
|
|
if (frameNum !== undefined) {
|
|
this._gotoFrame(frameNum);
|
|
}
|
|
},
|
|
isPlaying: function () {
|
|
return this._isPlaying;
|
|
},
|
|
nextFrame: function () {
|
|
this.stop();
|
|
if (this._currentFrame < this._framesLoaded) {
|
|
this._gotoFrame(this._currentFrame + 1);
|
|
}
|
|
},
|
|
nextScene: function () {
|
|
if (this._scenes && this._currentScene < this._scenes.length - 1) {
|
|
this._gotoFrame(this._scenes[this._currentScene + 1]._startFrame);
|
|
}
|
|
},
|
|
play: function () {
|
|
if (this._isPlaying || this._complete && this._totalFrames <= 1) {
|
|
return;
|
|
}
|
|
this._isPlaying = true;
|
|
this._addEventListener('advanceFrame', this._onAdvanceFrame);
|
|
},
|
|
prevFrame: function () {
|
|
this.stop();
|
|
if (this._currentFrame > 1) {
|
|
this._gotoFrame(this._currentFrame - 1);
|
|
}
|
|
},
|
|
prevScene: function () {
|
|
if (this._scenes && this._currentScene > 0) {
|
|
this._gotoFrame(this._scenes[this._currentScene - 1]._startFrame);
|
|
}
|
|
},
|
|
stop: function () {
|
|
if (!this._isPlaying || this._complete && this._totalFrames <= 1) {
|
|
return;
|
|
}
|
|
this._isPlaying = false;
|
|
this._removeEventListener('advanceFrame', this._onAdvanceFrame);
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
currentFrame: desc(def, 'currentFrame'),
|
|
framesLoaded: desc(def, 'framesLoaded'),
|
|
totalFrames: desc(def, 'totalFrames'),
|
|
trackAsMenu: desc(def, 'trackAsMenu'),
|
|
scenes: desc(def, 'scenes'),
|
|
currentScene: desc(def, 'currentScene'),
|
|
currentLabel: desc(def, 'currentLabel'),
|
|
currentFrameLabel: desc(def, 'currentFrameLabel'),
|
|
enabled: desc(def, 'enabled'),
|
|
isPlaying: desc(def, 'isPlaying'),
|
|
play: def.play,
|
|
stop: def.stop,
|
|
nextFrame: def.nextFrame,
|
|
prevFrame: def.prevFrame,
|
|
gotoAndPlay: def.gotoAndPlay,
|
|
gotoAndStop: def.gotoAndStop,
|
|
addFrameScript: def.addFrameScript,
|
|
prevScene: def.prevScene,
|
|
nextScene: def.nextScene
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var MovieClipSoundStream = function () {
|
|
var MP3_MIME_TYPE = 'audio/mpeg';
|
|
function openMediaSource(soundStream, mediaSource) {
|
|
var sourceBuffer;
|
|
try {
|
|
sourceBuffer = mediaSource.addSourceBuffer(MP3_MIME_TYPE);
|
|
soundStream.mediaSource = mediaSource;
|
|
soundStream.sourceBuffer = sourceBuffer;
|
|
soundStream.rawFrames.forEach(function (data) {
|
|
sourceBuffer.appendBuffer(data);
|
|
});
|
|
delete soundStream.rawFrames;
|
|
} catch (e) {
|
|
console.error('MediaSource mp3 playback is not supported: ' + e);
|
|
}
|
|
}
|
|
function syncTime(element, movieClip) {
|
|
var initialized = false;
|
|
var startMediaTime, startRealTime;
|
|
element.addEventListener('timeupdate', function (e) {
|
|
if (!initialized) {
|
|
startMediaTime = element.currentTime;
|
|
startRealTime = performance.now();
|
|
initialized = true;
|
|
movieClip._stage._frameScheduler.startTrackDelta();
|
|
return;
|
|
}
|
|
var mediaDelta = element.currentTime - startMediaTime;
|
|
var realDelta = performance.now() - startRealTime;
|
|
movieClip._stage._frameScheduler.setDelta(realDelta - mediaDelta * 1000);
|
|
});
|
|
element.addEventListener('pause', function (e) {
|
|
movieClip._stage._frameScheduler.endTrackDelta();
|
|
initialized = false;
|
|
});
|
|
element.addEventListener('seeking', function (e) {
|
|
movieClip._stage._frameScheduler.endTrackDelta();
|
|
initialized = false;
|
|
});
|
|
}
|
|
function MovieClipSoundStream(streamInfo, movieClip) {
|
|
this.movieClip = movieClip;
|
|
this.data = {
|
|
sampleRate: streamInfo.sampleRate,
|
|
channels: streamInfo.channels
|
|
};
|
|
this.seekIndex = [];
|
|
this.position = 0;
|
|
var isMP3 = streamInfo.format === 'mp3';
|
|
if (isMP3 && PLAY_USING_AUDIO_TAG) {
|
|
var element = document.createElement('audio');
|
|
element.preload = 'metadata';
|
|
element.loop = false;
|
|
syncTime(element, movieClip);
|
|
if (element.canPlayType(MP3_MIME_TYPE)) {
|
|
this.element = element;
|
|
if (typeof MediaSource !== 'undefined') {
|
|
var mediaSource = new MediaSource();
|
|
mediaSource.addEventListener('sourceopen', openMediaSource.bind(null, this, mediaSource));
|
|
element.src = URL.createObjectURL(mediaSource);
|
|
} else {
|
|
console.warn('MediaSource is not supported');
|
|
}
|
|
this.rawFrames = [];
|
|
return;
|
|
}
|
|
}
|
|
var totalSamples = streamInfo.samplesCount * streamInfo.channels;
|
|
this.data.pcm = new Float32Array(totalSamples);
|
|
if (isMP3) {
|
|
var soundStream = this;
|
|
soundStream.decoderPosition = 0;
|
|
soundStream.decoderSession = new MP3DecoderSession();
|
|
soundStream.decoderSession.onframedata = function (frameData) {
|
|
var position = soundStream.decoderPosition;
|
|
soundStream.data.pcm.set(frameData, position);
|
|
soundStream.decoderPosition = position + frameData.length;
|
|
}.bind(this);
|
|
soundStream.decoderSession.onerror = function (error) {
|
|
console.error('ERROR: MP3DecoderSession: ' + error);
|
|
};
|
|
}
|
|
}
|
|
MovieClipSoundStream.prototype = {
|
|
appendBlock: function (frameNum, streamBlock) {
|
|
var streamPosition = this.position;
|
|
this.seekIndex[frameNum] = streamPosition + streamBlock.seek * this.data.channels;
|
|
this.position = streamPosition + streamBlock.samplesCount * this.data.channels;
|
|
if (this.sourceBuffer) {
|
|
this.sourceBuffer.appendBuffer(streamBlock.data);
|
|
return;
|
|
}
|
|
if (this.rawFrames) {
|
|
this.rawFrames.push(streamBlock.data);
|
|
return;
|
|
}
|
|
var decoderSession = this.decoderSession;
|
|
if (decoderSession) {
|
|
decoderSession.pushAsync(streamBlock.data);
|
|
} else {
|
|
this.data.pcm.set(streamBlock.pcm, streamPosition);
|
|
}
|
|
},
|
|
playFrame: function (frameNum) {
|
|
if (isNaN(this.seekIndex[frameNum])) {
|
|
return;
|
|
}
|
|
var PAUSE_WHEN_OF_SYNC_GREATER = 1;
|
|
var PLAYBACK_ADJUSTMENT = 0.25;
|
|
var element = this.element;
|
|
if (element) {
|
|
var soundStreamData = this.data;
|
|
var time = this.seekIndex[frameNum] / soundStreamData.sampleRate / soundStreamData.channels;
|
|
if (!this.channel && (this.movieClip._complete || this.sourceBuffer)) {
|
|
if (!this.sourceBuffer) {
|
|
var blob = new Blob(this.rawFrames);
|
|
element.src = URL.createObjectURL(blob);
|
|
}
|
|
var symbolClass = flash.media.SoundChannel.class;
|
|
var channel = symbolClass.createAsSymbol({
|
|
element: element
|
|
});
|
|
symbolClass.instanceConstructor.call(channel);
|
|
this.channel = channel;
|
|
this.expectedFrame = 0;
|
|
this.waitFor = 0;
|
|
} else if (this.sourceBuffer || !isNaN(element.duration)) {
|
|
if (this.mediaSource && this.movieClip._complete) {
|
|
this.mediaSource.endOfStream();
|
|
this.mediaSource = null;
|
|
}
|
|
var elementTime = element.currentTime;
|
|
if (this.expectedFrame !== frameNum) {
|
|
if (element.paused) {
|
|
element.play();
|
|
element.addEventListener('playing', function setTime(e) {
|
|
element.removeEventListener('playing', setTime);
|
|
element.currentTime = time;
|
|
});
|
|
} else {
|
|
element.currentTime = time;
|
|
}
|
|
} else if (this.waitFor > 0) {
|
|
if (this.waitFor <= time) {
|
|
if (element.paused) {
|
|
element.play();
|
|
}
|
|
this.waitFor = 0;
|
|
}
|
|
} else if (elementTime - time > PAUSE_WHEN_OF_SYNC_GREATER) {
|
|
console.warn('Sound is faster than frames by ' + (elementTime - time));
|
|
this.waitFor = elementTime - PLAYBACK_ADJUSTMENT;
|
|
element.pause();
|
|
} else if (time - elementTime > PAUSE_WHEN_OF_SYNC_GREATER) {
|
|
console.warn('Sound is slower than frames by ' + (time - elementTime));
|
|
element.currentTime = time + PLAYBACK_ADJUSTMENT;
|
|
}
|
|
this.expectedFrame = frameNum + 1;
|
|
}
|
|
} else if (!this.sound) {
|
|
var symbolClass = flash.media.Sound.class;
|
|
var sound = symbolClass.createAsSymbol(this.data);
|
|
symbolClass.instanceConstructor.call(sound);
|
|
var channel = sound.play();
|
|
this.sound = sound;
|
|
this.channel = channel;
|
|
}
|
|
}
|
|
};
|
|
return MovieClipSoundStream;
|
|
}();
|
|
var NativeMenuDefinition = function () {
|
|
return {
|
|
__class__: 'flash.display.NativeMenu',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var NativeMenuItemDefinition = function () {
|
|
return {
|
|
__class__: 'flash.display.NativeMenuItem',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
enabled: {
|
|
get: function enabled() {
|
|
somewhatImplemented('NativeMenuItem.enabled');
|
|
return this._enabled;
|
|
},
|
|
set: function enabled(isSeparator) {
|
|
somewhatImplemented('NativeMenuItem.enabled');
|
|
this._enabled = isSeparator;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var SceneDefinition = function () {
|
|
return {
|
|
__class__: 'flash.display.Scene',
|
|
initialize: function () {
|
|
this._startFrame = 1;
|
|
this._endFrame = 1;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {}
|
|
},
|
|
script: {
|
|
static: {},
|
|
instance: {
|
|
name: {
|
|
get: function name() {
|
|
notImplemented('Scene.name');
|
|
return this._name;
|
|
}
|
|
},
|
|
labels: {
|
|
get: function labels() {
|
|
notImplemented('Scene.labels');
|
|
return this._labels;
|
|
}
|
|
},
|
|
numFrames: {
|
|
get: function numFrames() {
|
|
notImplemented('Scene.numFrames');
|
|
return this._numFrames;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var ShaderDefinition = function () {
|
|
return {
|
|
__class__: 'flash.display.Shader',
|
|
initialize: function () {
|
|
this._data = null;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
data: {
|
|
get: function data() {
|
|
return this._data;
|
|
},
|
|
set: function data(p) {
|
|
this._data = p;
|
|
}
|
|
},
|
|
precisionHint: {
|
|
get: function precisionHint() {
|
|
return this._precisionHint;
|
|
},
|
|
set: function precisionHint(p) {
|
|
this._precisionHint = p;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var ShaderDataDefinition = function () {
|
|
return {
|
|
__class__: 'flash.display.ShaderData',
|
|
initialize: function () {
|
|
this._byteCode = null;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
_setByteCode: function _setByteCode(code) {
|
|
this._byteCode = code;
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var ShapeDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.display.Shape',
|
|
initialize: function () {
|
|
var graphics = this._graphics = new flash.display.Graphics();
|
|
graphics._parent = this;
|
|
var s = this.symbol;
|
|
if (s && s.paths) {
|
|
graphics._paths = s.paths;
|
|
for (var i = 0; i < s.paths.length; i++) {
|
|
s.paths[i] = finishShapePath(s.paths[i], s.dictionaryResolved);
|
|
}
|
|
graphics.bbox = s.bbox;
|
|
graphics.strokeBbox = s.strokeBbox;
|
|
if (this._stage && this._stage._quality === 'low' && !graphics._bitmap)
|
|
graphics._cacheAsBitmap(this._bbox);
|
|
this.ratio = s.ratio || 0;
|
|
}
|
|
}
|
|
};
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
graphics: {
|
|
get: function () {
|
|
return this._graphics;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var SimpleButtonDefinition = function () {
|
|
var AVM1KeyCodeMap = [
|
|
0,
|
|
37,
|
|
39,
|
|
36,
|
|
35,
|
|
45,
|
|
46,
|
|
0,
|
|
8,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
13,
|
|
38,
|
|
40,
|
|
33,
|
|
34,
|
|
9,
|
|
27
|
|
];
|
|
var AVM1MouseTransitionEvents = [
|
|
0,
|
|
0,
|
|
1,
|
|
128,
|
|
64,
|
|
0,
|
|
0,
|
|
32,
|
|
2,
|
|
0,
|
|
0,
|
|
4,
|
|
256,
|
|
16,
|
|
8,
|
|
0
|
|
];
|
|
return {
|
|
__class__: 'flash.display.SimpleButton',
|
|
initialize: function () {
|
|
this._useHandCursor = true;
|
|
this._enabled = true;
|
|
this._trackAsMenu = false;
|
|
this._upState = null;
|
|
this._overState = null;
|
|
this._downState = null;
|
|
this._hitTestState = null;
|
|
this._currentButtonState = 'up';
|
|
this._mouseChildren = false;
|
|
this._buttonMode = true;
|
|
this._prevAvm1StateCode = 0;
|
|
this._avm1StateCode = 0;
|
|
this._avm1MouseEvents = null;
|
|
this._isContainer = true;
|
|
var s = this.symbol;
|
|
if (s) {
|
|
var states = s.states;
|
|
if (states.down) {
|
|
this._downState = this._constructState(states.down, this);
|
|
}
|
|
if (states.hitTest) {
|
|
this._hitTestState = this._constructState(states.hitTest, this);
|
|
}
|
|
if (states.over) {
|
|
this._overState = this._constructState(states.over, this);
|
|
}
|
|
if (states.up) {
|
|
this._upState = this._constructState(states.up, this);
|
|
}
|
|
}
|
|
if (this._loader && !this._loader._isAvm2Enabled && s && s.buttonActions) {
|
|
this._addEventListener('addedToStage', function (e) {
|
|
this._initAvm1Events(s.buttonActions);
|
|
}.bind(this), false);
|
|
}
|
|
},
|
|
_constructState: function constructState(symbolInfo) {
|
|
var symbolClass = avm2.systemDomain.findClass(symbolInfo.className) ? avm2.systemDomain.getClass(symbolInfo.className) : avm2.applicationDomain.getClass(symbolInfo.className);
|
|
var instance = symbolClass.createAsSymbol(symbolInfo.props);
|
|
symbolClass.instanceConstructor.call(instance);
|
|
if (instance._children.length === 1) {
|
|
instance = instance._children[0];
|
|
instance._parent = null;
|
|
instance._index = -1;
|
|
}
|
|
return instance;
|
|
},
|
|
_updateButton: function updateButton() {
|
|
var state = null;
|
|
switch (this._currentButtonState) {
|
|
case 'up':
|
|
state = this._upState;
|
|
break;
|
|
case 'over':
|
|
state = this._overState;
|
|
break;
|
|
case 'down':
|
|
state = this._downState;
|
|
break;
|
|
}
|
|
if (!state) {
|
|
return;
|
|
}
|
|
var currentChild = this._children[0];
|
|
if (currentChild) {
|
|
if (currentChild === state) {
|
|
return;
|
|
}
|
|
if (this._stage) {
|
|
this._stage._removeFromStage(currentChild);
|
|
}
|
|
currentChild._invalidateTransform();
|
|
}
|
|
if (!state) {
|
|
this._children.shift();
|
|
return;
|
|
}
|
|
this._children[0] = state;
|
|
state._parent = this;
|
|
state._invalidateTransform();
|
|
if (this._stage) {
|
|
this._stage._addToStage(state);
|
|
}
|
|
},
|
|
_gotoButtonState: function gotoButtonState(buttonState) {
|
|
this._invalidateBounds();
|
|
this._currentButtonState = buttonState;
|
|
this._updateButton();
|
|
if (this._avm1MouseEvents) {
|
|
this._processAvm1MouseEvents(this._avm1MouseEvents);
|
|
}
|
|
},
|
|
_getRegion: function getRegion(targetCoordSpace) {
|
|
if (!this._hitTestState) {
|
|
return {
|
|
xMin: 0,
|
|
yMin: 0,
|
|
xMax: 0,
|
|
yMax: 0
|
|
};
|
|
}
|
|
var b = this._hitTestState.getBounds(null);
|
|
return this._getTransformedRect(b, targetCoordSpace);
|
|
},
|
|
_getAS2Object: function () {
|
|
if (!this.$as2Object) {
|
|
new avm1lib.AS2Button(this);
|
|
}
|
|
return this.$as2Object;
|
|
},
|
|
_initAvm1Events: function (buttonActions) {
|
|
var loader = this._loader;
|
|
var avm1Context = loader._avm1Context;
|
|
var keyEvents = null;
|
|
for (var i = 0; i < buttonActions.length; i++) {
|
|
var buttonAction = buttonActions[i];
|
|
var fn = function (actionBlock) {
|
|
return executeActions(actionBlock, avm1Context, this._getAS2Object());
|
|
}.bind(this.parent, buttonAction.actionsData);
|
|
var mouseEventFlags = buttonAction.mouseEventFlags;
|
|
if (mouseEventFlags) {
|
|
var mouseEvents = this._avm1MouseEvents || (this._avm1MouseEvents = []);
|
|
mouseEvents.push({
|
|
flags: mouseEventFlags,
|
|
listener: fn
|
|
});
|
|
}
|
|
var keyPress = buttonAction.keyPress;
|
|
if (keyPress) {
|
|
keyEvents = keyEvents || (keyEvents = []);
|
|
keyEvents.push({
|
|
keyCode: AVM1KeyCodeMap[keyPress] || 0,
|
|
charCode: keyPress,
|
|
listener: fn
|
|
});
|
|
}
|
|
}
|
|
if (keyEvents) {
|
|
var keyListener = function (e) {
|
|
for (var i = 0; i < keyEvents.length; i++) {
|
|
var keyEvent = keyEvents[i];
|
|
if (keyEvent.keyCode ? keyEvent.keyCode === e.keyCode : keyEvent.charCode === e.charCode) {
|
|
keyEvent.listener();
|
|
}
|
|
}
|
|
};
|
|
var KeyboardEventClass = flash.events.KeyboardEvent;
|
|
this.stage._addEventListener(KeyboardEventClass.class.KEY_DOWN, keyListener, false);
|
|
this._addEventListener('removedFromStage', function (stage) {
|
|
stage._removeEventListener(KeyboardEventClass.class.KEY_DOWN, keyListener, false);
|
|
}.bind(this, this.stage), false);
|
|
}
|
|
},
|
|
_processAvm1MouseEvents: function (mouseEvents) {
|
|
var prevAvm1StateCode = this._avm1StateCode;
|
|
var avm1StateCode = (this._currentButtonState === 'down' ? 1 : 0) | (this._currentButtonState !== 'up' ? 2 : 0);
|
|
if (prevAvm1StateCode !== avm1StateCode) {
|
|
this._prevAvm1StateCode = prevAvm1StateCode;
|
|
this._avm1StateCode = avm1StateCode;
|
|
var flag = AVM1MouseTransitionEvents[prevAvm1StateCode << 2 | avm1StateCode];
|
|
for (var i = 0; i < mouseEvents.length; i++) {
|
|
var mouseEvent = mouseEvents[i];
|
|
if ((mouseEvent.flags & flag) !== 0) {
|
|
mouseEvent.listener();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
instance: {
|
|
_updateButton: function _updateButton() {
|
|
this._updateButton();
|
|
},
|
|
useHandCursor: {
|
|
get: function useHandCursor() {
|
|
return this._useHandCursor;
|
|
},
|
|
set: function useHandCursor(value) {
|
|
this._useHandCursor = value;
|
|
}
|
|
},
|
|
enabled: {
|
|
get: function enabled() {
|
|
return this._enabled;
|
|
},
|
|
set: function enabled(value) {
|
|
this._enabled = value;
|
|
}
|
|
},
|
|
trackAsMenu: {
|
|
get: function trackAsMenu() {
|
|
notImplemented('SimpleButton.trackAsMenu');
|
|
return this._trackAsMenu;
|
|
},
|
|
set: function trackAsMenu(value) {
|
|
notImplemented('SimpleButton.trackAsMenu');
|
|
this._trackAsMenu = value;
|
|
}
|
|
},
|
|
upState: {
|
|
get: function upState() {
|
|
return this._upState;
|
|
},
|
|
set: function upState(value) {
|
|
this._upState = value;
|
|
this._updateButton();
|
|
}
|
|
},
|
|
overState: {
|
|
get: function overState() {
|
|
return this._overState;
|
|
},
|
|
set: function overState(value) {
|
|
this._overState = value;
|
|
this._updateButton();
|
|
}
|
|
},
|
|
downState: {
|
|
get: function downState() {
|
|
return this._downState;
|
|
},
|
|
set: function downState(value) {
|
|
this._downState = value;
|
|
this._updateButton();
|
|
}
|
|
},
|
|
hitTestState: {
|
|
get: function hitTestState() {
|
|
return this._hitTestState;
|
|
},
|
|
set: function hitTestState(value) {
|
|
if (value === this._hitTestState) {
|
|
return;
|
|
}
|
|
this._invalidate();
|
|
this._hitTestState = value;
|
|
}
|
|
},
|
|
soundTransform: {
|
|
get: function soundTransform() {
|
|
notImplemented('SimpleButton.soundTransform');
|
|
return this._soundTransform;
|
|
},
|
|
set: function soundTransform(value) {
|
|
notImplemented('SimpleButton.soundTransform');
|
|
this._soundTransform = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var SpriteDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.display.Sprite',
|
|
initialize: function () {
|
|
this._buttonMode = false;
|
|
this._hitArea = null;
|
|
this._useHandCursor = true;
|
|
this._hitTarget = null;
|
|
this._currentDisplayList = null;
|
|
var s = this.symbol;
|
|
if (s) {
|
|
this._graphics = s.graphics || new flash.display.Graphics();
|
|
if (s.timeline) {
|
|
var displayList = s.timeline[0];
|
|
if (displayList) {
|
|
var depths = displayList.depths;
|
|
for (var i = 0; i < depths.length; i++) {
|
|
var cmd = displayList[depths[i]];
|
|
if (cmd) {
|
|
var displayListItem = this._addTimelineChild(cmd);
|
|
displayListItem.next = this._currentDisplayList;
|
|
this._currentDisplayList = displayListItem;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
this._graphics = new flash.display.Graphics();
|
|
}
|
|
this._graphics._parent = this;
|
|
},
|
|
_addTimelineChild: function addTimelineChild(cmd, index) {
|
|
var symbolInfo = cmd.symbolInfo;
|
|
var props = Object.create(symbolInfo.props);
|
|
props.symbolId = cmd.symbolId;
|
|
props.depth = cmd.depth;
|
|
if (cmd.clip) {
|
|
props.clipDepth = cmd.clipDepth;
|
|
}
|
|
if (cmd.hasCxform) {
|
|
props.cxform = cmd.cxform;
|
|
}
|
|
if (cmd.hasMatrix) {
|
|
props.currentTransform = cmd.matrix;
|
|
}
|
|
if (cmd.hasName) {
|
|
props.name = cmd.name;
|
|
}
|
|
if (cmd.hasRatio) {
|
|
props.ratio = cmd.ratio / 65535;
|
|
}
|
|
if (cmd.blend) {
|
|
props.blendMode = cmd.blendMode;
|
|
}
|
|
var displayListItem = {
|
|
cmd: cmd,
|
|
depth: cmd.depth,
|
|
className: symbolInfo.className,
|
|
props: props,
|
|
events: cmd.events,
|
|
obj: null
|
|
};
|
|
if (index !== undefined) {
|
|
this._children.splice(index, 0, displayListItem);
|
|
} else {
|
|
this._children.push(displayListItem);
|
|
}
|
|
this._sparse = true;
|
|
return displayListItem;
|
|
},
|
|
_constructChildren: function () {
|
|
if (!this._sparse) {
|
|
return;
|
|
}
|
|
var loader = this._loader;
|
|
var children = this._children;
|
|
for (var i = 0; i < children.length; i++) {
|
|
var displayListItem = children[i];
|
|
Counter.count('constructChild');
|
|
if (flash.display.DisplayObject.class.isInstanceOf(displayListItem)) {
|
|
displayListItem._index = i;
|
|
} else {
|
|
var symbolClass = avm2.systemDomain.findClass(displayListItem.className) ? avm2.systemDomain.getClass(displayListItem.className) : avm2.applicationDomain.getClass(displayListItem.className);
|
|
var props = Object.create(displayListItem.props);
|
|
var name = props.name;
|
|
props.animated = true;
|
|
props.owned = true;
|
|
props.parent = this;
|
|
props.stage = this._stage;
|
|
if (this._level > -1) {
|
|
props.level = this._level + 1;
|
|
}
|
|
props.index = i;
|
|
var instance = symbolClass.createAsSymbol(props);
|
|
if (name) {
|
|
this[Multiname.getPublicQualifiedName(name)] = instance;
|
|
}
|
|
symbolClass.instanceConstructor.call(instance);
|
|
if (flash.display.BitmapData.class.isInstanceOf(instance)) {
|
|
var bitmapData = instance;
|
|
instance = flash.display.Bitmap.class.createAsSymbol(props);
|
|
flash.display.Bitmap.class.instanceConstructor.call(instance, bitmapData);
|
|
}
|
|
if (!loader._isAvm2Enabled) {
|
|
this._initAvm1Bindings(instance, name, displayListItem.events);
|
|
instance._dispatchEvent('init');
|
|
instance._dispatchEvent('construct');
|
|
instance._needLoadEvent = true;
|
|
} else {
|
|
instance._dispatchEvent('load');
|
|
}
|
|
instance._dispatchEvent('added', undefined, true);
|
|
if (this._stage) {
|
|
this._stage._addToStage(instance);
|
|
}
|
|
children[i] = instance;
|
|
displayListItem.obj = instance;
|
|
}
|
|
}
|
|
this._sparse = false;
|
|
},
|
|
_postConstructChildren: function () {
|
|
var loader = this._loader;
|
|
if (!loader || loader._isAvm2Enabled) {
|
|
return;
|
|
}
|
|
var children = this._children;
|
|
for (var i = 0; i < children.length; i++) {
|
|
var instance = children[i];
|
|
if (instance._needLoadEvent) {
|
|
instance._needLoadEvent = false;
|
|
instance._dispatchEvent('load');
|
|
}
|
|
}
|
|
},
|
|
_duplicate: function (name, depth, initObject) {
|
|
var loader = this._loader;
|
|
var parent = this._parent;
|
|
var children = parent._children;
|
|
var symbolClass = this.class;
|
|
var symbolInfo = this.symbol;
|
|
var props = Object.create(symbolInfo);
|
|
props.name = name;
|
|
props.parent = parent;
|
|
props.depth = depth;
|
|
var instance = symbolClass.createAsSymbol(props);
|
|
if (name && loader && !loader._isAvm2Enabled && !parent.asHasProperty(undefined, name, 0, false)) {
|
|
parent.asSetPublicProperty(name, instance);
|
|
}
|
|
symbolClass.instanceConstructor.call(instance);
|
|
instance._index = children.length;
|
|
children.push(instance);
|
|
if (!loader._isAvm2Enabled) {
|
|
parent._initAvm1Bindings(instance, name, symbolInfo && symbolInfo.events);
|
|
instance._dispatchEvent('init');
|
|
instance._dispatchEvent('construct');
|
|
}
|
|
instance._dispatchEvent('load');
|
|
instance._dispatchEvent('added');
|
|
if (this._stage) {
|
|
instance._invalidate();
|
|
}
|
|
return instance;
|
|
},
|
|
_insertChildAtDepth: function (child, depth) {
|
|
this.addChild(child);
|
|
var name = child._name;
|
|
var loader = this._loader;
|
|
if (name && loader && !loader._isAvm2Enabled && !this._getAS2Object().asHasProperty(undefined, name, 0, true)) {
|
|
this._getAS2Object().asSetPublicProperty(name, child._getAS2Object());
|
|
}
|
|
},
|
|
_initAvm1Bindings: function (instance, name, events) {
|
|
var loader = this._loader;
|
|
var avm1Context = loader._avm1Context;
|
|
var symbolProps = instance.symbol;
|
|
if (symbolProps && symbolProps.variableName) {
|
|
instance._getAS2Object().asSetPublicProperty('variable', symbolProps.variableName);
|
|
}
|
|
if (events) {
|
|
var eventsBound = [];
|
|
for (var i = 0; i < events.length; i++) {
|
|
var event = events[i];
|
|
if (event.eoe) {
|
|
break;
|
|
}
|
|
var fn = function (actionBlock) {
|
|
return executeActions(actionBlock, avm1Context, this._getAS2Object());
|
|
}.bind(instance, event.actionsData);
|
|
for (var eventName in event) {
|
|
if (eventName.indexOf('on') !== 0 || !event[eventName])
|
|
continue;
|
|
var avm2EventName = eventName[2].toLowerCase() + eventName.substring(3);
|
|
if (avm2EventName === 'enterFrame') {
|
|
avm2EventName = 'frameConstructed';
|
|
}
|
|
var avm2EventTarget = instance;
|
|
if (avm2EventName === 'mouseDown' || avm2EventName === 'mouseUp' || avm2EventName === 'mouseMove') {
|
|
avm2EventTarget = this._stage;
|
|
}
|
|
avm2EventTarget._addEventListener(avm2EventName, fn, false);
|
|
eventsBound.push({
|
|
name: avm2EventName,
|
|
fn: fn,
|
|
target: avm2EventTarget
|
|
});
|
|
}
|
|
}
|
|
if (eventsBound.length > 0) {
|
|
instance._addEventListener('removed', function (eventsBound) {
|
|
for (var i = 0; i < eventsBound.length; i++) {
|
|
eventsBound[i].target._removeEventListener(eventsBound[i].name, eventsBound[i].fn, false);
|
|
}
|
|
}.bind(instance, eventsBound), false);
|
|
}
|
|
}
|
|
if (name && this._getAS2Object && instance._getAS2Object) {
|
|
this._getAS2Object().asSetPublicProperty(name, instance._getAS2Object());
|
|
}
|
|
},
|
|
_gotoButtonState: function gotoButtonState(stateName) {
|
|
},
|
|
get buttonMode() {
|
|
return this._buttonMode;
|
|
},
|
|
set buttonMode(val) {
|
|
this._buttonMode = val;
|
|
},
|
|
get graphics() {
|
|
return this._graphics;
|
|
},
|
|
get hitArea() {
|
|
return this._hitArea;
|
|
},
|
|
set hitArea(val) {
|
|
if (this._hitArea === val) {
|
|
return;
|
|
}
|
|
if (val && val._hitTarget) {
|
|
val._hitTarget.hitArea = null;
|
|
}
|
|
this._hitArea = val;
|
|
if (val) {
|
|
val._hitTarget = this;
|
|
}
|
|
},
|
|
get soundTransform() {
|
|
notImplemented();
|
|
},
|
|
set soundTransform(val) {
|
|
notImplemented();
|
|
},
|
|
get useHandCursor() {
|
|
return this._useHandCursor;
|
|
},
|
|
set useHandCursor(val) {
|
|
this._useHandCursor = val;
|
|
if (this._stage) {
|
|
this._stage._mouseMoved = true;
|
|
}
|
|
},
|
|
startDrag: function (lockCenter, bounds) {
|
|
notImplemented();
|
|
},
|
|
startTouchDrag: function (touchPointID, lockCenter, bounds) {
|
|
notImplemented();
|
|
},
|
|
stopDrag: function () {
|
|
notImplemented();
|
|
},
|
|
stopTouchDrag: function (touchPointID) {
|
|
notImplemented();
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
graphics: desc(def, 'graphics'),
|
|
buttonMode: desc(def, 'buttonMode'),
|
|
dropTarget: desc(def, 'dropTarget'),
|
|
startDrag: def.startDrag,
|
|
stopDrag: def.stopDrag,
|
|
startTouchDrag: def.startTouchDrag,
|
|
stopTouchDrag: def.stopTouchDrag,
|
|
constructChildren: def._constructChildren,
|
|
hitArea: desc(def, 'hitArea'),
|
|
useHandCursor: desc(def, 'useHandCursor'),
|
|
soundTransform: desc(def, 'soundTransform')
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var StageDefinition = function () {
|
|
return {
|
|
__class__: 'flash.display.Stage',
|
|
initialize: function () {
|
|
this._frameRate = 24;
|
|
this._scaleMode = 'showAll';
|
|
this._align = '';
|
|
this._stageWidth = 0;
|
|
this._stageHeight = 0;
|
|
this._quality = 'high';
|
|
this._color = 4294967295;
|
|
this._stage = this;
|
|
this._deferRenderEvent = false;
|
|
this._focus = null;
|
|
this._showDefaultContextMenu = true;
|
|
this._displayState = 'normal';
|
|
this._colorCorrection = 'default';
|
|
this._stageFocusRect = true;
|
|
this._fullScreenSourceRect = null;
|
|
this._wmodeGPU = false;
|
|
this._root = null;
|
|
this._qtree = null;
|
|
this._invalidRegions = new RegionCluster();
|
|
this._mouseMoved = false;
|
|
this._mouseTarget = this;
|
|
this._mouseEvents = [];
|
|
this._cursor = 'auto';
|
|
this._stageVideos = [];
|
|
this._concatenatedTransform.invalid = false;
|
|
},
|
|
_setup: function setup(ctx, options) {
|
|
this._qtree = new QuadTree(0, 0, this._stageWidth, this._stageHeight, null);
|
|
this._invalid = true;
|
|
},
|
|
_addToStage: function addToStage(displayObject) {
|
|
displayObject._stage = this;
|
|
var parent = displayObject._parent;
|
|
displayObject._level = parent._level + 1;
|
|
displayObject._invalid = true;
|
|
var children = displayObject._children;
|
|
for (var i = 0; i < children.length; i++) {
|
|
var child = children[i];
|
|
if (child._stage === null) {
|
|
this._addToStage(child);
|
|
}
|
|
}
|
|
displayObject._dispatchEvent('addedToStage');
|
|
},
|
|
_removeFromStage: function removeFromStage(displayObject) {
|
|
var children = displayObject._children;
|
|
for (var i = 0; i < children.length; i++) {
|
|
var child = children[i];
|
|
if (child._stage) {
|
|
this._removeFromStage(children[i]);
|
|
}
|
|
}
|
|
displayObject._dispatchEvent('removedFromStage');
|
|
displayObject._stage = null;
|
|
displayObject._level = -1;
|
|
if (displayObject._region) {
|
|
this._qtree.remove(displayObject._region);
|
|
this._invalidRegions.insert(displayObject._region);
|
|
displayObject._region = null;
|
|
}
|
|
},
|
|
_processInvalidations: function processInvalidations(refreshStage) {
|
|
var qtree = this._qtree;
|
|
var invalidRegions = this._invalidRegions;
|
|
var stack = [];
|
|
var zindex = 0;
|
|
var children = this._children;
|
|
var i = children.length;
|
|
while (i--) {
|
|
var child = children[i];
|
|
if (refreshStage) {
|
|
child._invalid = true;
|
|
}
|
|
child._invisible = !child._visible;
|
|
stack.push(child);
|
|
}
|
|
while (stack.length) {
|
|
var node = stack.pop();
|
|
var m = node._concatenatedTransform;
|
|
var children = node._children;
|
|
var i = children.length;
|
|
while (i--) {
|
|
var child = children[i];
|
|
if (!flash.display.DisplayObject.class.isInstanceOf(child)) {
|
|
continue;
|
|
}
|
|
if (node._invalid) {
|
|
child._invalid = true;
|
|
}
|
|
if (m.invalid) {
|
|
child._concatenatedTransform.invalid = true;
|
|
}
|
|
child._invisible = node._invisible || !child._visible;
|
|
stack.push(child);
|
|
}
|
|
if (node._level && m.invalid) {
|
|
var m2 = node._currentTransform;
|
|
var m3 = node._parent._concatenatedTransform;
|
|
m.a = m2.a * m3.a + m2.b * m3.c;
|
|
m.b = m2.a * m3.b + m2.b * m3.d;
|
|
m.c = m2.c * m3.a + m2.d * m3.c;
|
|
m.d = m2.d * m3.d + m2.c * m3.b;
|
|
m.tx = m2.tx * m3.a + m3.tx + m2.ty * m3.c;
|
|
m.ty = m2.ty * m3.d + m3.ty + m2.tx * m3.b;
|
|
m.invalid = false;
|
|
}
|
|
var invalidRegion = node._region;
|
|
var currentRegion = node._getRegion(m);
|
|
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;
|
|
if (node._invalid) {
|
|
if (invalidRegion) {
|
|
invalidRegions.insert(invalidRegion);
|
|
}
|
|
if (!hidden && (!invalidRegion || currentRegion.xMin !== invalidRegion.xMin || currentRegion.yMin !== invalidRegion.yMin || currentRegion.xMax !== invalidRegion.xMax || currentRegion.yMax !== invalidRegion.yMax)) {
|
|
invalidRegions.insert(currentRegion);
|
|
}
|
|
}
|
|
if (hidden) {
|
|
if (invalidRegion) {
|
|
qtree.remove(invalidRegion);
|
|
node._region = null;
|
|
}
|
|
} else if (invalidRegion) {
|
|
invalidRegion.xMin = currentRegion.xMin;
|
|
invalidRegion.xMax = currentRegion.xMax;
|
|
invalidRegion.yMin = currentRegion.yMin;
|
|
invalidRegion.yMax = currentRegion.yMax;
|
|
qtree.update(invalidRegion);
|
|
} else {
|
|
currentRegion.obj = node;
|
|
qtree.insert(currentRegion);
|
|
node._region = currentRegion;
|
|
}
|
|
node._zindex = zindex++;
|
|
}
|
|
var invalidPath = new ShapePath();
|
|
if (refreshStage) {
|
|
invalidPath.rect(0, 0, this._stageWidth, this._stageHeight);
|
|
invalidRegions.reset();
|
|
return invalidPath;
|
|
}
|
|
var redrawRegions = invalidRegions.retrieve();
|
|
for (var i = 0; i < redrawRegions.length; i++) {
|
|
var region = redrawRegions[i];
|
|
var xMin = region.xMin - region.xMin % 20 - 40;
|
|
var yMin = region.yMin - region.yMin % 20 - 40;
|
|
var xMax = region.xMax - region.xMax % 20 + 80;
|
|
var yMax = region.yMax - region.yMax % 20 + 80;
|
|
var intersectees = qtree.retrieve(xMin, xMax, yMin, yMax);
|
|
for (var j = 0; j < intersectees.length; j++) {
|
|
var item = intersectees[j];
|
|
item.obj._invalid = true;
|
|
}
|
|
invalidPath.rect(xMin, yMin, xMax - xMin, yMax - yMin);
|
|
}
|
|
invalidRegions.reset();
|
|
return invalidPath;
|
|
},
|
|
_handleMouseButtons: function () {
|
|
if (this._mouseEvents.length === 0) {
|
|
return;
|
|
}
|
|
var eventType = this._mouseEvents.shift();
|
|
switch (eventType) {
|
|
case 'mousedown':
|
|
if (this._mouseTarget._buttonMode) {
|
|
this._mouseTarget._gotoButtonState('down');
|
|
}
|
|
this._mouseTarget._dispatchEvent('mouseDown');
|
|
break;
|
|
case 'mouseup':
|
|
if (this._mouseTarget._buttonMode) {
|
|
this._mouseTarget._gotoButtonState('over');
|
|
}
|
|
this._mouseTarget._dispatchEvent('mouseUp');
|
|
break;
|
|
}
|
|
},
|
|
_handleMouse: function handleMouse() {
|
|
var mouseX = this._mouseX;
|
|
var mouseY = this._mouseY;
|
|
var candidates = this._qtree.retrieve(mouseX, mouseX, mouseY, mouseY);
|
|
var objectsUnderMouse = [];
|
|
for (var i = 0; i < candidates.length; i++) {
|
|
var item = candidates[i];
|
|
var displayObject = item.obj;
|
|
var isUnderMouse = false;
|
|
if (flash.display.SimpleButton.class.isInstanceOf(displayObject)) {
|
|
if (!displayObject._enabled) {
|
|
continue;
|
|
}
|
|
var hitArea = displayObject._hitTestState;
|
|
hitArea._parent = displayObject;
|
|
isUnderMouse = hitArea._hitTest(true, mouseX, mouseY, true);
|
|
hitArea._parent = null;
|
|
} else {
|
|
isUnderMouse = displayObject._hitTest(true, mouseX, mouseY, true);
|
|
}
|
|
if (isUnderMouse) {
|
|
var currentNode = displayObject;
|
|
var lastEnabled = null;
|
|
if (!flash.display.InteractiveObject.class.isInstanceOf(currentNode)) {
|
|
lastEnabled = currentNode;
|
|
currentNode = currentNode._parent;
|
|
}
|
|
do {
|
|
if (!currentNode._mouseEnabled) {
|
|
lastEnabled = null;
|
|
} else if (lastEnabled === null) {
|
|
lastEnabled = currentNode;
|
|
}
|
|
currentNode = currentNode._parent;
|
|
} while (currentNode);
|
|
objectsUnderMouse.push(lastEnabled);
|
|
}
|
|
}
|
|
var target;
|
|
if (objectsUnderMouse.length) {
|
|
objectsUnderMouse.sort(sortByZindex);
|
|
var i = objectsUnderMouse.length;
|
|
while (i--) {
|
|
target = null;
|
|
var currentNode = objectsUnderMouse[i];
|
|
if (!flash.display.InteractiveObject.class.isInstanceOf(currentNode)) {
|
|
var j = i;
|
|
while (j--) {
|
|
if (objectsUnderMouse[j]._parent === currentNode._parent && flash.display.InteractiveObject.class.isInstanceOf(objectsUnderMouse[j])) {
|
|
currentNode = objectsUnderMouse[j];
|
|
i = j;
|
|
}
|
|
}
|
|
}
|
|
do {
|
|
if (flash.display.InteractiveObject.class.isInstanceOf(currentNode)) {
|
|
if ((!target || !currentNode._mouseChildren) && !currentNode._hitArea) {
|
|
target = currentNode;
|
|
}
|
|
}
|
|
currentNode = currentNode._parent;
|
|
} while (currentNode);
|
|
if (target !== objectsUnderMouse[i] && flash.display.SimpleButton.class.isInstanceOf(target)) {
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (!target) {
|
|
target = this;
|
|
} else if (target._hitTarget) {
|
|
target = target._hitTarget;
|
|
}
|
|
if (target === this._mouseTarget) {
|
|
target._dispatchEvent('mouseMove');
|
|
} else {
|
|
if (this._mouseTarget._buttonMode) {
|
|
this._mouseTarget._gotoButtonState('up');
|
|
}
|
|
this._mouseTarget._dispatchEvent('mouseOut');
|
|
var nodeLeft = this._mouseTarget;
|
|
var containerLeft = nodeLeft._parent;
|
|
var nodeEntered = target;
|
|
var containerEntered = nodeEntered._parent;
|
|
var cursor = 'auto';
|
|
while (nodeLeft._level >= 0 && nodeLeft !== containerEntered) {
|
|
if (nodeLeft._hasEventListener('rollOut')) {
|
|
nodeLeft._dispatchEvent('rollOut');
|
|
}
|
|
nodeLeft = nodeLeft._parent;
|
|
}
|
|
while (nodeEntered._level >= 0 && nodeEntered !== containerLeft) {
|
|
if (nodeEntered._hasEventListener('rollOver')) {
|
|
nodeEntered._dispatchEvent('rollOver');
|
|
}
|
|
if (nodeEntered._buttonMode && nodeEntered._useHandCursor) {
|
|
cursor = 'pointer';
|
|
}
|
|
nodeEntered = nodeEntered._parent;
|
|
}
|
|
if (target._buttonMode) {
|
|
target._gotoButtonState('over');
|
|
}
|
|
target._dispatchEvent('mouseOver');
|
|
this._mouseTarget = target;
|
|
this._cursor = cursor;
|
|
}
|
|
},
|
|
_as2SetLevel: function (level, loader) {
|
|
somewhatImplemented('Stage._as2SetLevel');
|
|
this.addChild(loader);
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
instance: {
|
|
invalidate: function invalidate() {
|
|
this._invalid = true;
|
|
this._deferRenderEvent = true;
|
|
},
|
|
isFocusInaccessible: function isFocusInaccessible() {
|
|
notImplemented('Stage.isFocusInaccessible');
|
|
},
|
|
set_displayState: function set_displayState(value) {
|
|
somewhatImplemented('Stage.set_displayState');
|
|
this._displayState = value;
|
|
},
|
|
get_simulatedFullScreenWidth: function get_simulatedFullScreenWidth() {
|
|
notImplemented('Stage.get_simulatedFullScreenWidth');
|
|
},
|
|
get_simulatedFullScreenHeight: function get_simulatedFullScreenHeight() {
|
|
notImplemented('Stage.get_simulatedFullScreenHeight');
|
|
},
|
|
removeChildAt: function removeChildAt(index) {
|
|
notImplemented('Stage.removeChildAt');
|
|
},
|
|
swapChildrenAt: function swapChildrenAt(index1, index2) {
|
|
notImplemented('Stage.swapChildrenAt');
|
|
},
|
|
requireOwnerPermissions: function requireOwnerPermissions() {
|
|
somewhatImplemented('Stage.requireOwnerPermissions');
|
|
},
|
|
frameRate: {
|
|
get: function frameRate() {
|
|
return this._frameRate;
|
|
},
|
|
set: function frameRate(value) {
|
|
this._frameRate = value;
|
|
}
|
|
},
|
|
scaleMode: {
|
|
get: function scaleMode() {
|
|
return this._scaleMode;
|
|
},
|
|
set: function scaleMode(value) {
|
|
this._scaleMode = value;
|
|
this._invalid = true;
|
|
}
|
|
},
|
|
align: {
|
|
get: function align() {
|
|
return this._align;
|
|
},
|
|
set: function align(value) {
|
|
this._align = value;
|
|
this._invalid = true;
|
|
}
|
|
},
|
|
stageWidth: {
|
|
get: function stageWidth() {
|
|
return this._stageWidth / 20;
|
|
},
|
|
set: function stageWidth(value) {
|
|
notImplemented('Stage.stageWidth');
|
|
this._stageWidth = value * 20 | 0;
|
|
}
|
|
},
|
|
stageHeight: {
|
|
get: function stageHeight() {
|
|
return this._stageHeight / 20;
|
|
},
|
|
set: function stageHeight(value) {
|
|
notImplemented('Stage.stageHeight');
|
|
this._stageHeight = value * 20 | 0;
|
|
}
|
|
},
|
|
showDefaultContextMenu: {
|
|
get: function showDefaultContextMenu() {
|
|
return this._showDefaultContextMenu;
|
|
},
|
|
set: function showDefaultContextMenu(value) {
|
|
somewhatImplemented('Stage.showDefaultContextMenu');
|
|
this._showDefaultContextMenu = value;
|
|
}
|
|
},
|
|
focus: {
|
|
get: function focus() {
|
|
return this._focus;
|
|
},
|
|
set: function focus(newFocus) {
|
|
somewhatImplemented('Stage.focus');
|
|
this._focus = newFocus;
|
|
}
|
|
},
|
|
colorCorrection: {
|
|
get: function colorCorrection() {
|
|
return this._colorCorrection;
|
|
},
|
|
set: function colorCorrection(value) {
|
|
notImplemented('Stage.colorCorrection');
|
|
this._colorCorrection = value;
|
|
}
|
|
},
|
|
colorCorrectionSupport: {
|
|
get: function colorCorrectionSupport() {
|
|
return false;
|
|
}
|
|
},
|
|
stageFocusRect: {
|
|
get: function stageFocusRect() {
|
|
return this._stageFocusRect;
|
|
},
|
|
set: function stageFocusRect(on) {
|
|
somewhatImplemented('Stage.stageFocusRect');
|
|
this._stageFocusRect = on;
|
|
}
|
|
},
|
|
quality: {
|
|
get: function quality() {
|
|
return this._quality;
|
|
},
|
|
set: function quality(value) {
|
|
somewhatImplemented('Stage.stageFocusRect');
|
|
this._quality = value;
|
|
}
|
|
},
|
|
displayState: {
|
|
get: function displayState() {
|
|
return this._displayState;
|
|
},
|
|
set: function displayState(value) {
|
|
this._displayState = value;
|
|
}
|
|
},
|
|
simulatedDisplayState: {
|
|
get: function simulatedDisplayState() {
|
|
notImplemented('Stage.simulatedDisplayState');
|
|
return this._simulatedDisplayState;
|
|
},
|
|
set: function simulatedDisplayState(value) {
|
|
notImplemented('Stage.simulatedDisplayState');
|
|
this._simulatedDisplayState = value;
|
|
}
|
|
},
|
|
fullScreenSourceRect: {
|
|
get: function fullScreenSourceRect() {
|
|
return this._fullScreenSourceRect;
|
|
},
|
|
set: function fullScreenSourceRect(value) {
|
|
notImplemented('Stage.fullScreenSourceRect');
|
|
this._fullScreenSourceRect = value;
|
|
}
|
|
},
|
|
simulatedFullScreenSourceRect: {
|
|
get: function simulatedFullScreenSourceRect() {
|
|
notImplemented('Stage.simulatedFullScreenSourceRect');
|
|
return this._simulatedFullScreenSourceRect;
|
|
},
|
|
set: function simulatedFullScreenSourceRect(value) {
|
|
notImplemented('Stage.simulatedFullScreenSourceRect');
|
|
this._simulatedFullScreenSourceRect = value;
|
|
}
|
|
},
|
|
stageVideos: {
|
|
get: function stageVideos() {
|
|
somewhatImplemented('Stage.stageVideos');
|
|
return this._stageVideos;
|
|
}
|
|
},
|
|
stage3Ds: {
|
|
get: function stage3Ds() {
|
|
notImplemented('Stage.stage3Ds');
|
|
return this._stage3Ds;
|
|
}
|
|
},
|
|
color: {
|
|
get: function color() {
|
|
return this._color;
|
|
},
|
|
set: function color(color) {
|
|
this._color = color;
|
|
this._invalid = true;
|
|
}
|
|
},
|
|
fullScreenWidth: {
|
|
get: function fullScreenWidth() {
|
|
notImplemented('Stage.fullScreenWidth');
|
|
return this._fullScreenWidth;
|
|
}
|
|
},
|
|
fullScreenHeight: {
|
|
get: function fullScreenHeight() {
|
|
notImplemented('Stage.fullScreenHeight');
|
|
return this._fullScreenHeight;
|
|
}
|
|
},
|
|
wmodeGPU: {
|
|
get: function wmodeGPU() {
|
|
somewhatImplemented('Stage.wmodeGPU');
|
|
return this._wmodeGPU;
|
|
}
|
|
},
|
|
softKeyboardRect: {
|
|
get: function softKeyboardRect() {
|
|
notImplemented('Stage.softKeyboardRect');
|
|
return this._softKeyboardRect;
|
|
}
|
|
},
|
|
allowsFullScreen: {
|
|
get: function allowsFullScreen() {
|
|
return false;
|
|
}
|
|
},
|
|
displayContextInfo: {
|
|
get: function displayContextInfo() {
|
|
notImplemented('Stage.displayContextInfo');
|
|
return this._displayContextInfo;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
{
|
|
var EventDefinition = function () {
|
|
return {
|
|
__class__: 'flash.events.Event',
|
|
initialize: function () {
|
|
this._stopPropagation = false;
|
|
this._stopImmediatePropagation = false;
|
|
this._isDefaultPrevented = false;
|
|
this._target = null;
|
|
this._currentTarget = null;
|
|
this._eventPhase = 2;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
instance: {
|
|
ctor: function ctor(type, bubbles, cancelable) {
|
|
Counter.count('Event: ' + type);
|
|
this._type = type;
|
|
this._bubbles = bubbles;
|
|
this._cancelable = cancelable;
|
|
},
|
|
stopPropagation: function stopPropagation() {
|
|
this._stopPropagation = true;
|
|
},
|
|
stopImmediatePropagation: function stopImmediatePropagation() {
|
|
this._stopImmediatePropagation = this._stopPropagation = true;
|
|
},
|
|
preventDefault: function preventDefault() {
|
|
if (this._cancelable)
|
|
this._isDefaultPrevented = true;
|
|
},
|
|
isDefaultPrevented: function isDefaultPrevented() {
|
|
return this._isDefaultPrevented;
|
|
},
|
|
type: {
|
|
get: function type() {
|
|
return this._type;
|
|
}
|
|
},
|
|
bubbles: {
|
|
get: function bubbles() {
|
|
return this._bubbles;
|
|
}
|
|
},
|
|
cancelable: {
|
|
get: function cancelable() {
|
|
return this._cancelable;
|
|
}
|
|
},
|
|
target: {
|
|
get: function target() {
|
|
return this._target;
|
|
}
|
|
},
|
|
currentTarget: {
|
|
get: function currentTarget() {
|
|
return this._currentTarget;
|
|
}
|
|
},
|
|
eventPhase: {
|
|
get: function eventPhase() {
|
|
return this._eventPhase;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
static: Glue.ALL,
|
|
instance: {
|
|
clone: 'open public clone'
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
}
|
|
var EventDispatcherDefinition = function () {
|
|
var mouseEvents = {
|
|
click: true,
|
|
contextMenu: true,
|
|
doubleClick: true,
|
|
middleClick: true,
|
|
middleMouseDown: true,
|
|
middleMouseUp: true,
|
|
mouseDown: true,
|
|
mouseMove: true,
|
|
mouseOut: true,
|
|
mouseOver: true,
|
|
mouseUp: true,
|
|
mouseWheel: true,
|
|
releaseOutside: true,
|
|
rightClick: true,
|
|
rightMouseDown: true,
|
|
rightMouseUp: true,
|
|
rollOut: false,
|
|
rollOver: false
|
|
};
|
|
function doDispatchEvent(dispatcher, event, eventClass, bubbles) {
|
|
var target = dispatcher._target;
|
|
var type = event._type || event;
|
|
var listeners = dispatcher._listeners[type];
|
|
if (bubbles || typeof event === 'string' && mouseEvents[event] || event._bubbles) {
|
|
var ancestors = [];
|
|
var currentNode = target._parent;
|
|
while (currentNode) {
|
|
if (currentNode._hasEventListener(type)) {
|
|
ancestors.push(currentNode);
|
|
}
|
|
currentNode = currentNode._parent;
|
|
}
|
|
if (!listeners && !ancestors.length) {
|
|
return true;
|
|
}
|
|
var keepPropagating = true;
|
|
var i = ancestors.length;
|
|
while (i-- && keepPropagating) {
|
|
var currentTarget = ancestors[i];
|
|
var queue = currentTarget._captureListeners[type];
|
|
keepPropagating = processListeners(queue, event, eventClass, bubbles, target, currentTarget, 1);
|
|
}
|
|
if (listeners && keepPropagating) {
|
|
keepPropagating = processListeners(listeners, event, eventClass, bubbles, target);
|
|
}
|
|
for (var i = 0; i < ancestors.length && keepPropagating; i++) {
|
|
var currentTarget = ancestors[i];
|
|
var queue = currentTarget._listeners[type];
|
|
keepPropagating = processListeners(queue, event, eventClass, bubbles, target, currentTarget, 3);
|
|
}
|
|
} else if (listeners) {
|
|
processListeners(listeners, event, eventClass, bubbles, target);
|
|
}
|
|
return !event._isDefaultPrevented;
|
|
}
|
|
function processListeners(queue, event, eventClass, bubbles, target, currentTarget, eventPhase) {
|
|
if (queue) {
|
|
queue = queue.slice();
|
|
var needsInit = true;
|
|
try {
|
|
for (var i = 0; i < queue.length; i++) {
|
|
var item = queue[i];
|
|
var methodInfo = item.handleEvent.methodInfo;
|
|
if (methodInfo) {
|
|
if (methodInfo.parameters.length) {
|
|
if (!methodInfo.parameters[0].isUsed) {
|
|
item.handleEvent();
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (needsInit) {
|
|
if (typeof event === 'string') {
|
|
if (eventClass) {
|
|
event = new eventClass(event);
|
|
} else {
|
|
if (mouseEvents[event]) {
|
|
event = new flash.events.MouseEvent(event, mouseEvents[event]);
|
|
if (target._stage) {
|
|
event._localX = target.mouseX;
|
|
event._localY = target.mouseY;
|
|
}
|
|
} else {
|
|
event = new flash.events.Event(event);
|
|
}
|
|
}
|
|
} else if (event._target) {
|
|
event = event.clone();
|
|
}
|
|
event._target = target;
|
|
event._currentTarget = currentTarget || target;
|
|
event._eventPhase = eventPhase || 2;
|
|
needsInit = false;
|
|
}
|
|
item.handleEvent(event);
|
|
if (event._stopImmediatePropagation) {
|
|
break;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
avm2.exceptions.push({
|
|
source: 'avm2',
|
|
message: e.message,
|
|
stack: e.stack
|
|
});
|
|
throw e;
|
|
}
|
|
}
|
|
return !event._stopPropagation;
|
|
}
|
|
return {
|
|
__class__: 'flash.events.EventDispatcher',
|
|
initialize: function () {
|
|
this._target = this;
|
|
this._listeners = {};
|
|
this._captureListeners = {};
|
|
},
|
|
_addEventListenerImpl: function addEventListenerImpl(type, listener, useCapture, priority) {
|
|
if (typeof listener !== 'function') {
|
|
throwError('TypeError', Errors.CheckTypeFailedError, listener, 'Function');
|
|
}
|
|
var listeners = useCapture ? this._captureListeners : this._listeners;
|
|
var queue = listeners[type];
|
|
var listenerObj = {
|
|
handleEvent: listener,
|
|
priority: priority || 0
|
|
};
|
|
if (queue) {
|
|
var level = queue.length;
|
|
var i = level;
|
|
while (i--) {
|
|
var item = queue[i];
|
|
if (item.handleEvent === listener) {
|
|
return;
|
|
}
|
|
if (priority > item.priority) {
|
|
level = i;
|
|
}
|
|
}
|
|
queue.splice(level, 0, listenerObj);
|
|
} else {
|
|
listeners[type] = [
|
|
listenerObj
|
|
];
|
|
}
|
|
},
|
|
_addEventListener: function addEventListener(type, listener, useCapture, priority) {
|
|
this._addEventListenerImpl(type, listener, useCapture, priority);
|
|
},
|
|
_removeEventListenerImpl: function removeEventListenerImpl(type, listener, useCapture) {
|
|
if (typeof listener !== 'function') {
|
|
throwError('TypeError', Errors.CheckTypeFailedError, listener, 'Function');
|
|
}
|
|
var listeners = useCapture ? this._captureListeners : this._listeners;
|
|
var queue = listeners[type];
|
|
if (queue) {
|
|
for (var i = 0; i < queue.length; i++) {
|
|
var item = queue[i];
|
|
if (item.handleEvent === listener) {
|
|
queue.splice(i, 1);
|
|
if (!queue.length) {
|
|
listeners[type] = null;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
_removeEventListener: function removeEventListener(type, listener, useCapture) {
|
|
this._removeEventListenerImpl(type, listener, useCapture);
|
|
},
|
|
_hasEventListener: function hasEventListener(type) {
|
|
return this._listeners[type] || this._captureListeners[type];
|
|
},
|
|
_dispatchEvent: function dispatchEvent(event, eventClass, bubbles) {
|
|
doDispatchEvent(this, event, eventClass, bubbles);
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
instance: {
|
|
ctor: function ctor(target) {
|
|
this._target = target || this;
|
|
},
|
|
addEventListener: function addEventListener(type, listener, useCapture, priority, useWeakReference) {
|
|
this._addEventListener(type, listener, useCapture, priority);
|
|
},
|
|
removeEventListener: function removeEventListener(type, listener, useCapture) {
|
|
this._removeEventListener(type, listener, useCapture);
|
|
},
|
|
hasEventListener: function hasEventListener(type) {
|
|
return this._hasEventListener(type);
|
|
},
|
|
willTrigger: function willTrigger(type) {
|
|
var currentNode = this._target;
|
|
do {
|
|
if (currentNode._hasEventListener(type)) {
|
|
return true;
|
|
}
|
|
} while (currentNode = currentNode._parent);
|
|
return false;
|
|
},
|
|
dispatchEventFunction: function dispatchEventFunction(event) {
|
|
return doDispatchEvent(this, event);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var KeyboardEventDefinition = function () {
|
|
return {
|
|
__class__: 'flash.events.KeyboardEvent',
|
|
__glue__: {
|
|
native: {
|
|
instance: {
|
|
updateAfterEvent: function updateAfterEvent() {
|
|
notImplemented('KeyboardEvent.updateAfterEvent');
|
|
},
|
|
charCode: {
|
|
get: function charCode() {
|
|
return this._charCode;
|
|
},
|
|
set: function charCode(value) {
|
|
this._charCode = value;
|
|
}
|
|
},
|
|
ctrlKey: {
|
|
get: function ctrlKey() {
|
|
return this._ctrlKey;
|
|
},
|
|
set: function ctrlKey(value) {
|
|
this._ctrlKey = value;
|
|
}
|
|
},
|
|
altKey: {
|
|
get: function altKey() {
|
|
return this._altKey;
|
|
},
|
|
set: function altKey(value) {
|
|
this._altKey = value;
|
|
}
|
|
},
|
|
shiftKey: {
|
|
get: function shiftKey() {
|
|
return this._shiftKey;
|
|
},
|
|
set: function shiftKey(value) {
|
|
this._shiftKey = value;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
static: Glue.ALL,
|
|
instance: {
|
|
keyCode: 'public keyCode'
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var MouseEventDefinition = function () {
|
|
return {
|
|
__class__: 'flash.events.MouseEvent',
|
|
initialize: function () {
|
|
this._localX = NaN;
|
|
this._localY = NaN;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
instance: {
|
|
updateAfterEvent: function updateAfterEvent() {
|
|
},
|
|
getStageX: function getStageX() {
|
|
if (this._target) {
|
|
var m = this._target._getConcatenatedTransform(null, false);
|
|
var x = m.a * this._localX + m.c * this._localY + m.tx;
|
|
return x / 20;
|
|
}
|
|
return this._localX / 20;
|
|
},
|
|
getStageY: function getStageY() {
|
|
if (this._target) {
|
|
var m = this._target._getConcatenatedTransform(null, false);
|
|
var y = m.d * this._localY + m.b * this._localX + m.ty;
|
|
return y / 20;
|
|
}
|
|
return this._localY / 20;
|
|
},
|
|
localX: {
|
|
get: function localX() {
|
|
return this._localX / 20;
|
|
},
|
|
set: function localX(value) {
|
|
this._localX = value * 20 | 0;
|
|
}
|
|
},
|
|
localY: {
|
|
get: function localY() {
|
|
return this._localY / 20;
|
|
},
|
|
set: function localY(value) {
|
|
this._localY = value * 20 | 0;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
static: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var TextEventDefinition = function () {
|
|
return {
|
|
__class__: 'flash.events.TextEvent',
|
|
__glue__: {
|
|
native: {
|
|
instance: {
|
|
copyNativeData: function copyNativeData(other) {
|
|
notImplemented('TextEvent.copyNativeData');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var TimerEventDefinition = function () {
|
|
return {
|
|
__class__: 'flash.events.TimerEvent',
|
|
__glue__: {
|
|
native: {
|
|
instance: {
|
|
updateAfterEvent: function updateAfterEvent() {
|
|
notImplemented('TimerEvent.updateAfterEvent');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
{
|
|
var ExternalInterfaceDefinition = function () {
|
|
function getAvailable() {
|
|
return true;
|
|
}
|
|
var initialized = false;
|
|
var registeredCallbacks = {};
|
|
function callIn(functionName, args) {
|
|
if (!registeredCallbacks.hasOwnProperty(functionName))
|
|
return;
|
|
return registeredCallbacks[functionName](functionName, args);
|
|
}
|
|
return {
|
|
__class__: 'flash.external.ExternalInterface',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
_initJS: function _initJS() {
|
|
if (initialized)
|
|
return;
|
|
TelemetryService.reportTelemetry({
|
|
topic: 'feature',
|
|
feature: EXTERNAL_INTERFACE_FEATURE
|
|
});
|
|
initialized = true;
|
|
FirefoxCom.initJS(callIn);
|
|
},
|
|
_getPropNames: function _getPropNames(obj) {
|
|
var keys = [];
|
|
forEachPublicProperty(obj, function (key) {
|
|
keys.push(key);
|
|
});
|
|
return keys;
|
|
},
|
|
_addCallback: function _addCallback(functionName, closure, hasNullCallback) {
|
|
FirefoxCom.request('externalCom', {
|
|
action: 'register',
|
|
functionName: functionName,
|
|
remove: hasNullCallback
|
|
});
|
|
if (hasNullCallback) {
|
|
delete registeredCallbacks[functionName];
|
|
} else {
|
|
registeredCallbacks[functionName] = closure;
|
|
}
|
|
},
|
|
_evalJS: function _evalJS(expression) {
|
|
return FirefoxCom.requestSync('externalCom', {
|
|
action: 'eval',
|
|
expression: expression
|
|
});
|
|
},
|
|
_callOut: function _callOut(request) {
|
|
return FirefoxCom.requestSync('externalCom', {
|
|
action: 'call',
|
|
request: request
|
|
});
|
|
},
|
|
available: {
|
|
get: getAvailable
|
|
},
|
|
objectID: {
|
|
get: function objectID() {
|
|
return FirefoxCom.requestSync('externalCom', {
|
|
action: 'getId'
|
|
});
|
|
}
|
|
},
|
|
activeX: {
|
|
get: function activeX() {
|
|
return false;
|
|
}
|
|
}
|
|
},
|
|
instance: {}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
}
|
|
{
|
|
var BevelFilterDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.filters.BevelFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
}
|
|
};
|
|
def.__glue__ = {};
|
|
return def;
|
|
}.call(this);
|
|
}
|
|
var BitmapFilterDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.filters.BitmapFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
}
|
|
};
|
|
def.__glue__ = {};
|
|
return def;
|
|
}.call(this);
|
|
var BlurFilterDefinition = function () {
|
|
return {
|
|
__class__: 'flash.filters.BlurFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
var bx = this._blurX * this._quality * 20;
|
|
var by = this._blurY * this._quality * 20;
|
|
bounds.xMin -= bx;
|
|
bounds.xMax += bx;
|
|
bounds.yMin -= by;
|
|
bounds.yMax += by;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
blurX: {
|
|
get: function blurX() {
|
|
return this._blurX;
|
|
},
|
|
set: function blurX(value) {
|
|
this._blurX = value;
|
|
}
|
|
},
|
|
blurY: {
|
|
get: function blurY() {
|
|
return this._blurY;
|
|
},
|
|
set: function blurY(value) {
|
|
this._blurY = value;
|
|
}
|
|
},
|
|
quality: {
|
|
get: function quality() {
|
|
return this._quality;
|
|
},
|
|
set: function quality(value) {
|
|
this._quality = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var ColorMatrixFilterDefinition = function () {
|
|
return {
|
|
__class__: 'flash.filters.ColorMatrixFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
instance: {
|
|
matrix: {
|
|
get: function matrix() {
|
|
return this._matrix;
|
|
},
|
|
set: function matrix(value) {
|
|
this._matrix = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var ConvolutionFilterDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.filters.ConvolutionFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
}
|
|
};
|
|
def.__glue__ = {};
|
|
return def;
|
|
}.call(this);
|
|
var DisplacementMapFilterDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.filters.DisplacementMapFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
}
|
|
};
|
|
def.__glue__ = {};
|
|
return def;
|
|
}.call(this);
|
|
var DropShadowFilterDefinition = function () {
|
|
return {
|
|
__class__: 'flash.filters.DropShadowFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
var a = this._angle * Math.PI / 180;
|
|
var dy = Math.sin(a) * this._distance;
|
|
var dx = Math.cos(a) * this._distance;
|
|
var bx = this._blurX * this._quality * 20;
|
|
var by = this._blurY * this._quality * 20;
|
|
bounds.xMin -= bx - (dx > 0 ? 0 : dx);
|
|
bounds.xMax += bx + Math.abs(dx);
|
|
bounds.yMin -= by - (dy > 0 ? 0 : dy);
|
|
bounds.yMax += by + Math.abs(dy);
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
instance: {
|
|
distance: {
|
|
get: function distance() {
|
|
return this._distance;
|
|
},
|
|
set: function distance(value) {
|
|
this._distance = value;
|
|
}
|
|
},
|
|
angle: {
|
|
get: function angle() {
|
|
return this._angle;
|
|
},
|
|
set: function angle(value) {
|
|
this._angle = value;
|
|
}
|
|
},
|
|
color: {
|
|
get: function color() {
|
|
return this._color;
|
|
},
|
|
set: function color(value) {
|
|
this._color = value;
|
|
}
|
|
},
|
|
alpha: {
|
|
get: function alpha() {
|
|
return this._alpha;
|
|
},
|
|
set: function alpha(value) {
|
|
this._alpha = value;
|
|
}
|
|
},
|
|
blurX: {
|
|
get: function blurX() {
|
|
return this._blurX;
|
|
},
|
|
set: function blurX(value) {
|
|
this._blurX = value;
|
|
}
|
|
},
|
|
blurY: {
|
|
get: function blurY() {
|
|
return this._blurY;
|
|
},
|
|
set: function blurY(value) {
|
|
this._blurY = value;
|
|
}
|
|
},
|
|
hideObject: {
|
|
get: function hideObject() {
|
|
return this._hideObject;
|
|
},
|
|
set: function hideObject(value) {
|
|
this._hideObject = value;
|
|
}
|
|
},
|
|
inner: {
|
|
get: function inner() {
|
|
return this._inner;
|
|
},
|
|
set: function inner(value) {
|
|
this._inner = value;
|
|
}
|
|
},
|
|
knockout: {
|
|
get: function knockout() {
|
|
return this._knockout;
|
|
},
|
|
set: function knockout(value) {
|
|
this._knockout = value;
|
|
}
|
|
},
|
|
quality: {
|
|
get: function quality() {
|
|
return this._quality;
|
|
},
|
|
set: function quality(value) {
|
|
this._quality = value;
|
|
}
|
|
},
|
|
strength: {
|
|
get: function strength() {
|
|
return this._strength;
|
|
},
|
|
set: function strength(value) {
|
|
this._strength = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var GlowFilterDefinition = function () {
|
|
return {
|
|
__class__: 'flash.filters.GlowFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
var bx = this._blurX * this._quality * 20;
|
|
var by = this._blurY * this._quality * 20;
|
|
bounds.xMin -= bx;
|
|
bounds.xMax += bx;
|
|
bounds.yMin -= by;
|
|
bounds.yMax += by;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
color: {
|
|
get: function color() {
|
|
return this._color;
|
|
},
|
|
set: function color(value) {
|
|
this._color = value;
|
|
}
|
|
},
|
|
alpha: {
|
|
get: function alpha() {
|
|
return this._alpha;
|
|
},
|
|
set: function alpha(value) {
|
|
this._alpha = value;
|
|
}
|
|
},
|
|
blurX: {
|
|
get: function blurX() {
|
|
return this._blurX;
|
|
},
|
|
set: function blurX(value) {
|
|
this._blurX = value;
|
|
}
|
|
},
|
|
blurY: {
|
|
get: function blurY() {
|
|
return this._blurY;
|
|
},
|
|
set: function blurY(value) {
|
|
this._blurY = value;
|
|
}
|
|
},
|
|
inner: {
|
|
get: function inner() {
|
|
return this._inner;
|
|
},
|
|
set: function inner(value) {
|
|
this._inner = value;
|
|
}
|
|
},
|
|
knockout: {
|
|
get: function knockout() {
|
|
return this._knockout;
|
|
},
|
|
set: function knockout(value) {
|
|
this._knockout = value;
|
|
}
|
|
},
|
|
quality: {
|
|
get: function quality() {
|
|
return this._quality;
|
|
},
|
|
set: function quality(value) {
|
|
this._quality = value;
|
|
}
|
|
},
|
|
strength: {
|
|
get: function strength() {
|
|
return this._strength;
|
|
},
|
|
set: function strength(value) {
|
|
this._strength = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var GradientBevelFilterDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.filters.GradientBevelFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
}
|
|
};
|
|
def.__glue__ = {};
|
|
return def;
|
|
}.call(this);
|
|
var GradientGlowFilterDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.filters.GradientGlowFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
}
|
|
};
|
|
def.__glue__ = {};
|
|
return def;
|
|
}.call(this);
|
|
var ShaderFilterDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.filters.ShaderFilter',
|
|
initialize: function () {
|
|
},
|
|
_updateFilterBounds: function (bounds) {
|
|
}
|
|
};
|
|
def.__glue__ = {};
|
|
return def;
|
|
}.call(this);
|
|
{
|
|
var ColorTransformDefinition = function () {
|
|
return {
|
|
__class__: 'flash.geom.ColorTransform',
|
|
__glue__: {
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
}
|
|
var MatrixDefinition = function () {
|
|
return {
|
|
__class__: 'flash.geom.Matrix',
|
|
__glue__: {
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var Matrix3DDefinition = function () {
|
|
var precision = 1e-7;
|
|
var transposeTransform = new Uint32Array([
|
|
0,
|
|
4,
|
|
8,
|
|
12,
|
|
1,
|
|
5,
|
|
9,
|
|
13,
|
|
2,
|
|
6,
|
|
10,
|
|
14,
|
|
3,
|
|
7,
|
|
11,
|
|
15
|
|
]);
|
|
function getRotationMatrix(theta, u, v, w, a, b, c) {
|
|
var u2 = u * u, v2 = v * v, w2 = w * w;
|
|
var L2 = u2 + v2 + w2, L = Math.sqrt(L2);
|
|
u /= L;
|
|
v /= L;
|
|
w /= L;
|
|
u2 /= L2;
|
|
v2 /= L2;
|
|
w2 /= L2;
|
|
var cos = Math.cos(theta), sin = Math.sin(theta);
|
|
return new flash.geom.Matrix3D([
|
|
u2 + (v2 + w2) * cos,
|
|
u * v * (1 - cos) + w * sin,
|
|
u * w * (1 - cos) - v * sin,
|
|
0,
|
|
u * v * (1 - cos) - w * sin,
|
|
v2 + (u2 + w2) * cos,
|
|
v * w * (1 - cos) + u * sin,
|
|
0,
|
|
u * w * (1 - cos) + v * sin,
|
|
v * w * (1 - cos) - u * sin,
|
|
w2 + (u2 + v2) * cos,
|
|
0,
|
|
(a * (v2 + w2) - u * (b * v + c * w)) * (1 - cos) + (b * w - c * v) * sin,
|
|
(b * (u2 + w2) - v * (a * u + c * w)) * (1 - cos) + (c * u - a * w) * sin,
|
|
(c * (u2 + v2) - w * (a * u + b * v)) * (1 - cos) + (a * v - b * u) * sin,
|
|
1
|
|
]);
|
|
}
|
|
return {
|
|
__class__: 'flash.geom.Matrix3D',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
interpolate: function interpolate(thisMat, toMat, percent) {
|
|
notImplemented('Matrix3D.interpolate');
|
|
}
|
|
},
|
|
instance: {
|
|
ctor: function ctor(v) {
|
|
this._matrix = new Float32Array(16);
|
|
if (v && v.length >= 16) {
|
|
this.copyRawDataFrom(v, 0, false);
|
|
} else {
|
|
this.identity();
|
|
}
|
|
},
|
|
clone: function clone() {
|
|
return new flash.geom.Matrix3D(this._matrix);
|
|
},
|
|
copyToMatrix3D: function copyToMatrix3D(dest) {
|
|
dest._matrix.set(this._matrix);
|
|
},
|
|
append: function append(lhs) {
|
|
var ma = lhs._matrix, mb = this._matrix, m = this._matrix;
|
|
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];
|
|
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];
|
|
m[0] = ma11 * mb11 + ma12 * mb21 + ma13 * mb31 + ma14 * mb41;
|
|
m[1] = ma21 * mb11 + ma22 * mb21 + ma23 * mb31 + ma24 * mb41;
|
|
m[2] = ma31 * mb11 + ma32 * mb21 + ma33 * mb31 + ma34 * mb41;
|
|
m[3] = ma41 * mb11 + ma42 * mb21 + ma43 * mb31 + ma44 * mb41;
|
|
m[4] = ma11 * mb12 + ma12 * mb22 + ma13 * mb32 + ma14 * mb42;
|
|
m[5] = ma21 * mb12 + ma22 * mb22 + ma23 * mb32 + ma24 * mb42;
|
|
m[6] = ma31 * mb12 + ma32 * mb22 + ma33 * mb32 + ma34 * mb42;
|
|
m[7] = ma41 * mb12 + ma42 * mb22 + ma43 * mb32 + ma44 * mb42;
|
|
m[8] = ma11 * mb13 + ma12 * mb23 + ma13 * mb33 + ma14 * mb43;
|
|
m[9] = ma21 * mb13 + ma22 * mb23 + ma23 * mb33 + ma24 * mb43;
|
|
m[10] = ma31 * mb13 + ma32 * mb23 + ma33 * mb33 + ma34 * mb43;
|
|
m[11] = ma41 * mb13 + ma42 * mb23 + ma43 * mb33 + ma44 * mb43;
|
|
m[12] = ma11 * mb14 + ma12 * mb24 + ma13 * mb34 + ma14 * mb44;
|
|
m[13] = ma21 * mb14 + ma22 * mb24 + ma23 * mb34 + ma24 * mb44;
|
|
m[14] = ma31 * mb14 + ma32 * mb24 + ma33 * mb34 + ma34 * mb44;
|
|
m[15] = ma41 * mb14 + ma42 * mb24 + ma43 * mb34 + ma44 * mb44;
|
|
},
|
|
prepend: function prepend(rhs) {
|
|
var ma = this._matrix, mb = rhs._matrix, m = this._matrix;
|
|
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];
|
|
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];
|
|
m[0] = ma11 * mb11 + ma12 * mb21 + ma13 * mb31 + ma14 * mb41;
|
|
m[1] = ma21 * mb11 + ma22 * mb21 + ma23 * mb31 + ma24 * mb41;
|
|
m[2] = ma31 * mb11 + ma32 * mb21 + ma33 * mb31 + ma34 * mb41;
|
|
m[3] = ma41 * mb11 + ma42 * mb21 + ma43 * mb31 + ma44 * mb41;
|
|
m[4] = ma11 * mb12 + ma12 * mb22 + ma13 * mb32 + ma14 * mb42;
|
|
m[5] = ma21 * mb12 + ma22 * mb22 + ma23 * mb32 + ma24 * mb42;
|
|
m[6] = ma31 * mb12 + ma32 * mb22 + ma33 * mb32 + ma34 * mb42;
|
|
m[7] = ma41 * mb12 + ma42 * mb22 + ma43 * mb32 + ma44 * mb42;
|
|
m[8] = ma11 * mb13 + ma12 * mb23 + ma13 * mb33 + ma14 * mb43;
|
|
m[9] = ma21 * mb13 + ma22 * mb23 + ma23 * mb33 + ma24 * mb43;
|
|
m[10] = ma31 * mb13 + ma32 * mb23 + ma33 * mb33 + ma34 * mb43;
|
|
m[11] = ma41 * mb13 + ma42 * mb23 + ma43 * mb33 + ma44 * mb43;
|
|
m[12] = ma11 * mb14 + ma12 * mb24 + ma13 * mb34 + ma14 * mb44;
|
|
m[13] = ma21 * mb14 + ma22 * mb24 + ma23 * mb34 + ma24 * mb44;
|
|
m[14] = ma31 * mb14 + ma32 * mb24 + ma33 * mb34 + ma34 * mb44;
|
|
m[15] = ma41 * mb14 + ma42 * mb24 + ma43 * mb34 + ma44 * mb44;
|
|
},
|
|
invert: function invert() {
|
|
var d = this.determinant;
|
|
if (Math.abs(d) < precision) {
|
|
return false;
|
|
}
|
|
d = 1 / d;
|
|
var m = this._matrix;
|
|
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];
|
|
m[0] = d * (m22 * (m33 * m44 - m43 * m34) - m32 * (m23 * m44 - m43 * m24) + m42 * (m23 * m34 - m33 * m24));
|
|
m[1] = -d * (m12 * (m33 * m44 - m43 * m34) - m32 * (m13 * m44 - m43 * m14) + m42 * (m13 * m34 - m33 * m14));
|
|
m[2] = d * (m12 * (m23 * m44 - m43 * m24) - m22 * (m13 * m44 - m43 * m14) + m42 * (m13 * m24 - m23 * m14));
|
|
m[3] = -d * (m12 * (m23 * m34 - m33 * m24) - m22 * (m13 * m34 - m33 * m14) + m32 * (m13 * m24 - m23 * m14));
|
|
m[4] = -d * (m21 * (m33 * m44 - m43 * m34) - m31 * (m23 * m44 - m43 * m24) + m41 * (m23 * m34 - m33 * m24));
|
|
m[5] = d * (m11 * (m33 * m44 - m43 * m34) - m31 * (m13 * m44 - m43 * m14) + m41 * (m13 * m34 - m33 * m14));
|
|
m[6] = -d * (m11 * (m23 * m44 - m43 * m24) - m21 * (m13 * m44 - m43 * m14) + m41 * (m13 * m24 - m23 * m14));
|
|
m[7] = d * (m11 * (m23 * m34 - m33 * m24) - m21 * (m13 * m34 - m33 * m14) + m31 * (m13 * m24 - m23 * m14));
|
|
m[8] = d * (m21 * (m32 * m44 - m42 * m34) - m31 * (m22 * m44 - m42 * m24) + m41 * (m22 * m34 - m32 * m24));
|
|
m[9] = -d * (m11 * (m32 * m44 - m42 * m34) - m31 * (m12 * m44 - m42 * m14) + m41 * (m12 * m34 - m32 * m14));
|
|
m[10] = d * (m11 * (m22 * m44 - m42 * m24) - m21 * (m12 * m44 - m42 * m14) + m41 * (m12 * m24 - m22 * m14));
|
|
m[11] = -d * (m11 * (m22 * m34 - m32 * m24) - m21 * (m12 * m34 - m32 * m14) + m31 * (m12 * m24 - m22 * m14));
|
|
m[12] = -d * (m21 * (m32 * m43 - m42 * m33) - m31 * (m22 * m43 - m42 * m23) + m41 * (m22 * m33 - m32 * m23));
|
|
m[13] = d * (m11 * (m32 * m43 - m42 * m33) - m31 * (m12 * m43 - m42 * m13) + m41 * (m12 * m33 - m32 * m13));
|
|
m[14] = -d * (m11 * (m22 * m43 - m42 * m23) - m21 * (m12 * m43 - m42 * m13) + m41 * (m12 * m23 - m22 * m13));
|
|
m[15] = d * (m11 * (m22 * m33 - m32 * m23) - m21 * (m12 * m33 - m32 * m13) + m31 * (m12 * m23 - m22 * m13));
|
|
return true;
|
|
},
|
|
identity: function identity() {
|
|
var m = this._matrix;
|
|
m[0] = m[5] = m[10] = m[15] = 1;
|
|
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;
|
|
},
|
|
decompose: function decompose(orientationStyle) {
|
|
notImplemented('Matrix3D.decompose');
|
|
},
|
|
recompose: function recompose(components, orientationStyle) {
|
|
notImplemented('Matrix3D.recompose');
|
|
},
|
|
appendTranslation: function appendTranslation(x, y, z) {
|
|
var m = this._matrix;
|
|
var m41 = m[3], m42 = m[7], m43 = m[11], m44 = m[15];
|
|
m[0] += x * m41;
|
|
m[1] += y * m41;
|
|
m[2] += z * m41;
|
|
m[4] += x * m42;
|
|
m[5] += y * m42;
|
|
m[6] += z * m42;
|
|
m[8] += x * m43;
|
|
m[9] += y * m43;
|
|
m[10] += z * m43;
|
|
m[12] += x * m44;
|
|
m[13] += y * m44;
|
|
m[14] += z * m44;
|
|
},
|
|
appendRotation: function appendRotation(degrees, axis, pivotPoint) {
|
|
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));
|
|
},
|
|
appendScale: function appendScale(xScale, yScale, zScale) {
|
|
var m = this._matrix;
|
|
m[0] *= xScale;
|
|
m[1] *= yScale;
|
|
m[2] *= zScale;
|
|
m[4] *= xScale;
|
|
m[5] *= yScale;
|
|
m[6] *= zScale;
|
|
m[8] *= xScale;
|
|
m[9] *= yScale;
|
|
m[10] *= zScale;
|
|
m[12] *= xScale;
|
|
m[13] *= yScale;
|
|
m[14] *= zScale;
|
|
},
|
|
prependTranslation: function prependTranslation(x, y, z) {
|
|
var m = this._matrix;
|
|
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];
|
|
m[12] += m11 * x + m12 * y + m13 * z;
|
|
m[13] += m21 * x + m22 * y + m23 * z;
|
|
m[14] += m31 * x + m32 * y + m33 * z;
|
|
m[15] += m41 * x + m42 * y + m43 * z;
|
|
},
|
|
prependRotation: function prependRotation(degrees, axis, pivotPoint) {
|
|
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));
|
|
},
|
|
prependScale: function prependScale(xScale, yScale, zScale) {
|
|
var m = this._matrix;
|
|
m[0] *= xScale;
|
|
m[1] *= xScale;
|
|
m[2] *= xScale;
|
|
m[3] *= xScale;
|
|
m[4] *= yScale;
|
|
m[5] *= yScale;
|
|
m[6] *= yScale;
|
|
m[7] *= yScale;
|
|
m[8] *= zScale;
|
|
m[9] *= zScale;
|
|
m[10] *= zScale;
|
|
m[11] *= zScale;
|
|
},
|
|
transformVector: function transformVector(v) {
|
|
var m = this._matrix;
|
|
var x = v.x, y = v.y, z = v.z;
|
|
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]);
|
|
},
|
|
deltaTransformVector: function deltaTransformVector(v) {
|
|
var m = this._matrix;
|
|
var x = v.x, y = v.y, z = v.z;
|
|
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);
|
|
},
|
|
transformVectors: function transformVectors(vin, vout) {
|
|
var m = this._matrix;
|
|
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];
|
|
for (var i = 0; i < vin.length - 2; i += 3) {
|
|
var x = vin.asGetNumericProperty(i), y = vin.asGetNumericProperty(i + 1), z = vin.asGetNumericProperty(i + 2);
|
|
vout.push(m11 * x + m12 * y + m13 * z + m14);
|
|
vout.push(m21 * x + m22 * y + m23 * z + m24);
|
|
vout.push(m31 * x + m32 * y + m33 * z + m34);
|
|
}
|
|
},
|
|
transpose: function transpose() {
|
|
var m = this._matrix;
|
|
var tmp;
|
|
tmp = m[1];
|
|
m[1] = m[4];
|
|
m[4] = tmp;
|
|
tmp = m[2];
|
|
m[2] = m[8];
|
|
m[5] = tmp;
|
|
tmp = m[3];
|
|
m[3] = m[12];
|
|
m[12] = tmp;
|
|
tmp = m[6];
|
|
m[6] = m[9];
|
|
m[9] = tmp;
|
|
tmp = m[7];
|
|
m[7] = m[13];
|
|
m[13] = tmp;
|
|
tmp = m[11];
|
|
m[11] = m[14];
|
|
m[14] = tmp;
|
|
},
|
|
pointAt: function pointAt(pos, at, up) {
|
|
notImplemented('Matrix3D.pointAt');
|
|
},
|
|
interpolateTo: function interpolateTo(toMat, percent) {
|
|
notImplemented('Matrix3D.interpolateTo');
|
|
},
|
|
copyFrom: function copyFrom(sourceMatrix3D) {
|
|
this._matrix.set(sourceMatrix3D._matrix);
|
|
},
|
|
copyRawDataTo: function copyRawDataTo(vector, index, transpose) {
|
|
var m = this._matrix;
|
|
if (transpose) {
|
|
for (var i = 0, j = index | 0; i < 16; i++, j++) {
|
|
vector.asSetNumericProperty(j, m[transposeTransform[i]]);
|
|
}
|
|
} else {
|
|
for (var i = 0, j = index | 0; i < 16; i++, j++) {
|
|
vector.asSetNumericProperty(j, m[i]);
|
|
}
|
|
}
|
|
},
|
|
copyRawDataFrom: function copyRawDataFrom(vector, index, transpose) {
|
|
var m = this._matrix;
|
|
if (transpose) {
|
|
for (var i = 0, j = index | 0; i < 16; i++, j++) {
|
|
m[transposeTransform[i]] = vector.asGetNumericProperty(j) || 0;
|
|
}
|
|
} else {
|
|
for (var i = 0, j = index | 0; i < 16; i++, j++) {
|
|
m[i] = vector.asGetNumericProperty(j) || 0;
|
|
}
|
|
}
|
|
},
|
|
copyRowTo: function copyRowTo(row, vector3D) {
|
|
var offset = row | 0;
|
|
var m = this._matrix;
|
|
vector3D.x = m[offset];
|
|
vector3D.y = m[offset + 4];
|
|
vector3D.z = m[offset + 8];
|
|
vector3D.w = m[offset + 12];
|
|
},
|
|
copyColumnTo: function copyColumnTo(column, vector3D) {
|
|
var offset = column << 2;
|
|
var m = this._matrix;
|
|
vector3D.x = m[offset];
|
|
vector3D.y = m[offset + 1];
|
|
vector3D.z = m[offset + 2];
|
|
vector3D.w = m[offset + 3];
|
|
},
|
|
copyRowFrom: function copyRowFrom(row, vector3D) {
|
|
var offset = row | 0;
|
|
var m = this._matrix;
|
|
m[offset] = vector3D.x;
|
|
m[offset + 4] = vector3D.y;
|
|
m[offset + 8] = vector3D.z;
|
|
m[offset + 12] = vector3D.w;
|
|
},
|
|
copyColumnFrom: function copyColumnFrom(column, vector3D) {
|
|
var offset = column << 2;
|
|
var m = this._matrix;
|
|
m[offset] = vector3D.x;
|
|
m[offset + 1] = vector3D.y;
|
|
m[offset + 2] = vector3D.z;
|
|
m[offset + 3] = vector3D.w;
|
|
},
|
|
rawData: {
|
|
get: function rawData() {
|
|
var result = new Float64Vector();
|
|
this.copyRawDataTo(result, 0, false);
|
|
return result;
|
|
},
|
|
set: function rawData(v) {
|
|
this.copyRawDataFrom(v, 0, false);
|
|
}
|
|
},
|
|
position: {
|
|
get: function position() {
|
|
var m = this._matrix;
|
|
return new flash.geom.Vector3D(m[12], m[13], m[14]);
|
|
},
|
|
set: function position(pos) {
|
|
var m = this._matrix;
|
|
m[12] = pos.x;
|
|
m[13] = pos.y;
|
|
m[14] = pos.z;
|
|
}
|
|
},
|
|
determinant: {
|
|
get: function determinant() {
|
|
var m = this._matrix;
|
|
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];
|
|
var d;
|
|
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));
|
|
return d;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var PointDefinition = function () {
|
|
return {
|
|
__class__: 'flash.geom.Point',
|
|
__glue__: {
|
|
script: {
|
|
static: Glue.ALL,
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var RectangleDefinition = function () {
|
|
return {
|
|
__class__: 'flash.geom.Rectangle',
|
|
__glue__: {
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var TransformDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.geom.Transform',
|
|
get colorTransform() {
|
|
var cxform = this._target._cxform;
|
|
if (cxform) {
|
|
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);
|
|
} else {
|
|
return new flash.geom.ColorTransform();
|
|
}
|
|
},
|
|
set colorTransform(val) {
|
|
var CTClass = avm2.systemDomain.getClass('flash.geom.ColorTransform');
|
|
if (!CTClass.isInstanceOf(val)) {
|
|
throwError('TypeError', Errors.CheckTypeFailedError, val, 'flash.geom.ColorTransform');
|
|
}
|
|
this._target._cxform = {
|
|
redMultiplier: val.redMultiplier * 256,
|
|
greenMultiplier: val.greenMultiplier * 256,
|
|
blueMultiplier: val.blueMultiplier * 256,
|
|
alphaMultiplier: val.alphaMultiplier * 256,
|
|
redOffset: val.redOffset,
|
|
greenOffset: val.greenOffset,
|
|
blueOffset: val.blueOffset,
|
|
alphaOffset: val.alphaOffset
|
|
};
|
|
this._target._invalidate();
|
|
},
|
|
get concatenatedColorTransform() {
|
|
var cxform = this.colorTransform;
|
|
cxform.concat(this._target.parent.transform.concatenatedColorTransform);
|
|
return cxform;
|
|
},
|
|
get concatenatedMatrix() {
|
|
if (this._target._current3DTransform) {
|
|
return null;
|
|
}
|
|
var m = this._target._getConcatenatedTransform(null, false);
|
|
return new flash.geom.Matrix(m.a, m.b, m.c, m.d, m.tx / 20, m.ty / 20);
|
|
},
|
|
get matrix() {
|
|
if (this._target._current3DTransform) {
|
|
return null;
|
|
}
|
|
var m = this._target._currentTransform;
|
|
return new flash.geom.Matrix(m.a, m.b, m.c, m.d, m.tx / 20, m.ty / 20);
|
|
},
|
|
set matrix(val) {
|
|
if (!flash.geom.Matrix.class.isInstanceOf(val)) {
|
|
throwError('TypeError', Errors.CheckTypeFailedError, val, 'flash.geom.Matrix');
|
|
}
|
|
var target = this._target;
|
|
target._invalidate();
|
|
target._setTransformMatrix(val, true);
|
|
target._current3DTransform = null;
|
|
target._animated = false;
|
|
},
|
|
get matrix3D() {
|
|
var m = this._target._current3DTransform;
|
|
return m && m.clone();
|
|
},
|
|
set matrix3D(val) {
|
|
var Matrix3DClass = avm2.systemDomain.getClass('flash.geom.Matrix3D');
|
|
if (!Matrix3DClass.isInstanceOf(val)) {
|
|
throwError('TypeError', Errors.CheckTypeFailedError, val, 'flash.geom.Matrix3D');
|
|
}
|
|
var raw = val.rawData;
|
|
this.matrix = new flash.geom.Matrix(raw.asGetPublicProperty(0), raw.asGetPublicProperty(1), raw.asGetPublicProperty(4), raw.asGetPublicProperty(5), raw.asGetPublicProperty(12), raw.asGetPublicProperty(13));
|
|
this._target._current3DTransform = val;
|
|
},
|
|
ctor: function (target) {
|
|
this._target = target;
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
colorTransform: desc(def, 'colorTransform'),
|
|
concatenatedColorTransform: desc(def, 'concatenatedColorTransform'),
|
|
concatenatedMatrix: desc(def, 'concatenatedMatrix'),
|
|
matrix: desc(def, 'matrix'),
|
|
matrix3D: desc(def, 'matrix3D'),
|
|
ctor: def.ctor
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var Vector3DDefinition = function () {
|
|
return {
|
|
__class__: 'flash.geom.Vector3D',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
{
|
|
var ID3InfoDefinition = function () {
|
|
return {
|
|
__glue__: {
|
|
script: {
|
|
instance: {
|
|
songName: 'public songName',
|
|
genre: 'public genre',
|
|
artist: 'public artist',
|
|
track: 'public track',
|
|
album: 'public album',
|
|
year: 'public year',
|
|
comment: 'public comment'
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
}
|
|
var MicrophoneDefinition = function () {
|
|
return {
|
|
__class__: 'flash.media.Microphone',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
getMicrophone: function getMicrophone(index) {
|
|
notImplemented('Microphone.getMicrophone');
|
|
},
|
|
getEnhancedMicrophone: function getEnhancedMicrophone(index) {
|
|
notImplemented('Microphone.getEnhancedMicrophone');
|
|
},
|
|
names: {
|
|
get: function names() {
|
|
notImplemented('Microphone.names');
|
|
}
|
|
},
|
|
isSupported: {
|
|
get: function isSupported() {
|
|
notImplemented('Microphone.isSupported');
|
|
}
|
|
}
|
|
},
|
|
instance: {
|
|
setSilenceLevel: function setSilenceLevel(silenceLevel, timeout) {
|
|
notImplemented('Microphone.setSilenceLevel');
|
|
},
|
|
setUseEchoSuppression: function setUseEchoSuppression(useEchoSuppression) {
|
|
notImplemented('Microphone.setUseEchoSuppression');
|
|
},
|
|
setLoopBack: function setLoopBack(state) {
|
|
notImplemented('Microphone.setLoopBack');
|
|
},
|
|
gain: {
|
|
set: function gain(gain) {
|
|
notImplemented('Microphone.gain');
|
|
this._gain = gain;
|
|
},
|
|
get: function gain() {
|
|
notImplemented('Microphone.gain');
|
|
return this._gain;
|
|
}
|
|
},
|
|
rate: {
|
|
set: function rate(rate) {
|
|
notImplemented('Microphone.rate');
|
|
this._rate = rate;
|
|
},
|
|
get: function rate() {
|
|
notImplemented('Microphone.rate');
|
|
return this._rate;
|
|
}
|
|
},
|
|
codec: {
|
|
set: function codec(codec) {
|
|
notImplemented('Microphone.codec');
|
|
this._codec = codec;
|
|
},
|
|
get: function codec() {
|
|
notImplemented('Microphone.codec');
|
|
return this._codec;
|
|
}
|
|
},
|
|
framesPerPacket: {
|
|
get: function framesPerPacket() {
|
|
notImplemented('Microphone.framesPerPacket');
|
|
return this._framesPerPacket;
|
|
},
|
|
set: function framesPerPacket(frames) {
|
|
notImplemented('Microphone.framesPerPacket');
|
|
this._framesPerPacket = frames;
|
|
}
|
|
},
|
|
encodeQuality: {
|
|
get: function encodeQuality() {
|
|
notImplemented('Microphone.encodeQuality');
|
|
return this._encodeQuality;
|
|
},
|
|
set: function encodeQuality(quality) {
|
|
notImplemented('Microphone.encodeQuality');
|
|
this._encodeQuality = quality;
|
|
}
|
|
},
|
|
noiseSuppressionLevel: {
|
|
get: function noiseSuppressionLevel() {
|
|
notImplemented('Microphone.noiseSuppressionLevel');
|
|
return this._noiseSuppressionLevel;
|
|
},
|
|
set: function noiseSuppressionLevel(level) {
|
|
notImplemented('Microphone.noiseSuppressionLevel');
|
|
this._noiseSuppressionLevel = level;
|
|
}
|
|
},
|
|
enableVAD: {
|
|
get: function enableVAD() {
|
|
notImplemented('Microphone.enableVAD');
|
|
return this._enableVAD;
|
|
},
|
|
set: function enableVAD(enable) {
|
|
notImplemented('Microphone.enableVAD');
|
|
this._enableVAD = enable;
|
|
}
|
|
},
|
|
activityLevel: {
|
|
get: function activityLevel() {
|
|
notImplemented('Microphone.activityLevel');
|
|
return this._activityLevel;
|
|
}
|
|
},
|
|
index: {
|
|
get: function index() {
|
|
notImplemented('Microphone.index');
|
|
return this._index;
|
|
}
|
|
},
|
|
muted: {
|
|
get: function muted() {
|
|
notImplemented('Microphone.muted');
|
|
return this._muted;
|
|
}
|
|
},
|
|
name: {
|
|
get: function name() {
|
|
notImplemented('Microphone.name');
|
|
return this._name;
|
|
}
|
|
},
|
|
silenceLevel: {
|
|
get: function silenceLevel() {
|
|
notImplemented('Microphone.silenceLevel');
|
|
return this._silenceLevel;
|
|
}
|
|
},
|
|
silenceTimeout: {
|
|
get: function silenceTimeout() {
|
|
notImplemented('Microphone.silenceTimeout');
|
|
return this._silenceTimeout;
|
|
}
|
|
},
|
|
useEchoSuppression: {
|
|
get: function useEchoSuppression() {
|
|
notImplemented('Microphone.useEchoSuppression');
|
|
return this._useEchoSuppression;
|
|
}
|
|
},
|
|
soundTransform: {
|
|
get: function soundTransform() {
|
|
notImplemented('Microphone.soundTransform');
|
|
return this._soundTransform;
|
|
},
|
|
set: function soundTransform(sndTransform) {
|
|
notImplemented('Microphone.soundTransform');
|
|
this._soundTransform = sndTransform;
|
|
}
|
|
},
|
|
enhancedOptions: {
|
|
get: function enhancedOptions() {
|
|
notImplemented('Microphone.enhancedOptions');
|
|
return this._enhancedOptions;
|
|
},
|
|
set: function enhancedOptions(options) {
|
|
notImplemented('Microphone.enhancedOptions');
|
|
this._enhancedOptions = options;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var PLAY_USING_AUDIO_TAG = true;
|
|
var SoundDefinition = function () {
|
|
function getAudioDescription(soundData, onComplete) {
|
|
var audioElement = document.createElement('audio');
|
|
if (!audioElement.canPlayType(soundData.mimeType)) {
|
|
onComplete({
|
|
duration: 0
|
|
});
|
|
return;
|
|
}
|
|
audioElement.preload = 'metadata';
|
|
var blob = new Blob([
|
|
soundData.data
|
|
], {
|
|
type: soundData.mimeType
|
|
});
|
|
audioElement.src = URL.createObjectURL(blob);
|
|
audioElement.load();
|
|
audioElement.addEventListener('loadedmetadata', function () {
|
|
onComplete({
|
|
duration: this.duration * 1000
|
|
});
|
|
});
|
|
}
|
|
var def = {
|
|
initialize: function initialize() {
|
|
this._playQueue = [];
|
|
this._url = null;
|
|
this._length = 0;
|
|
this._bytesTotal = 0;
|
|
this._bytesLoaded = 0;
|
|
this._id3 = new flash.media.ID3Info();
|
|
var s = this.symbol;
|
|
if (s) {
|
|
var soundData = {};
|
|
if (s.pcm) {
|
|
soundData.sampleRate = s.sampleRate;
|
|
soundData.channels = s.channels;
|
|
soundData.pcm = s.pcm;
|
|
soundData.end = s.pcm.length;
|
|
}
|
|
soundData.completed = true;
|
|
if (s.packaged) {
|
|
soundData.data = s.packaged.data.buffer;
|
|
soundData.mimeType = s.packaged.mimeType;
|
|
}
|
|
var _this = this;
|
|
getAudioDescription(soundData, function (description) {
|
|
_this._length = description.duration;
|
|
});
|
|
this._soundData = soundData;
|
|
}
|
|
TelemetryService.reportTelemetry({
|
|
topic: 'feature',
|
|
feature: SOUND_FEATURE
|
|
});
|
|
},
|
|
close: function close() {
|
|
somewhatImplemented('Sound.close');
|
|
},
|
|
extract: function extract(target, length, startPosition) {
|
|
notImplemented('Sound.extract');
|
|
},
|
|
_load: function _load(request, checkPolicyFile, bufferTime) {
|
|
if (!request) {
|
|
return;
|
|
}
|
|
var _this = this;
|
|
var stream = this._stream = new flash.net.URLStream();
|
|
var ByteArrayClass = avm2.systemDomain.getClass('flash.utils.ByteArray');
|
|
var data = ByteArrayClass.createInstance();
|
|
var dataPosition = 0;
|
|
var mp3DecodingSession = null;
|
|
var soundData = {
|
|
completed: false
|
|
};
|
|
stream._addEventListener('progress', function (event) {
|
|
_this._bytesLoaded = event[Multiname.getPublicQualifiedName('bytesLoaded')];
|
|
_this._bytesTotal = event[Multiname.getPublicQualifiedName('bytesTotal')];
|
|
if (!PLAY_USING_AUDIO_TAG && !mp3DecodingSession) {
|
|
mp3DecodingSession = decodeMP3(soundData, function (duration, final) {
|
|
if (_this._length === 0) {
|
|
_this._soundData = soundData;
|
|
_this._playQueue.forEach(function (item) {
|
|
item.channel._playSoundDataViaChannel(soundData, item.startTime);
|
|
});
|
|
}
|
|
_this._length = final ? duration * 1000 : Math.max(duration, mp3DecodingSession.estimateDuration(_this._bytesTotal)) * 1000;
|
|
});
|
|
}
|
|
var bytesAvailable = stream.bytesAvailable;
|
|
stream.readBytes(data, dataPosition, bytesAvailable);
|
|
if (mp3DecodingSession) {
|
|
mp3DecodingSession.pushData(new Uint8Array(data.a, dataPosition, bytesAvailable));
|
|
}
|
|
dataPosition += bytesAvailable;
|
|
_this._dispatchEvent(event);
|
|
});
|
|
stream._addEventListener('complete', function (event) {
|
|
_this._dispatchEvent(event);
|
|
soundData.data = data.a;
|
|
soundData.mimeType = 'audio/mpeg';
|
|
soundData.completed = true;
|
|
if (PLAY_USING_AUDIO_TAG) {
|
|
_this._soundData = soundData;
|
|
getAudioDescription(soundData, function (description) {
|
|
_this._length = description.duration;
|
|
});
|
|
_this._playQueue.forEach(function (item) {
|
|
item.channel._playSoundDataViaAudio(soundData, item.startTime);
|
|
});
|
|
}
|
|
if (mp3DecodingSession) {
|
|
mp3DecodingSession.close();
|
|
}
|
|
});
|
|
stream.load(request);
|
|
},
|
|
loadCompressedDataFromByteArray: function loadCompressedDataFromByteArray(bytes, bytesLength) {
|
|
notImplemented('Sound#loadCompressedDataFromByteArray');
|
|
},
|
|
loadPCMFromByteArray: function loadPCMFromByteArray(bytes, samples, format, stereo, sampleRate) {
|
|
notImplemented('Sound#loadPCMFromByteArray');
|
|
},
|
|
play: function play(startTime, loops, soundTransform) {
|
|
startTime = startTime || 0;
|
|
loops = loops || 0;
|
|
var channel = new flash.media.SoundChannel();
|
|
channel._sound = this;
|
|
channel._soundTransform = isNullOrUndefined(soundTransform) ? new flash.media.SoundTransform() : soundTransform;
|
|
this._playQueue.push({
|
|
channel: channel,
|
|
startTime: startTime
|
|
});
|
|
if (this._soundData) {
|
|
if (PLAY_USING_AUDIO_TAG)
|
|
channel._playSoundDataViaAudio(this._soundData, startTime, loops);
|
|
else
|
|
channel._playSoundDataViaChannel(this._soundData, startTime, loops);
|
|
}
|
|
return channel;
|
|
},
|
|
get bytesLoaded() {
|
|
return this._bytesLoaded;
|
|
},
|
|
get bytesTotal() {
|
|
return this._bytesTotal;
|
|
},
|
|
get id3() {
|
|
return this._id3;
|
|
},
|
|
get isBuffering() {
|
|
notImplemented('Sound#isBuffering');
|
|
},
|
|
get isURLInaccessible() {
|
|
notImplemented('Sound#isURLInaccessible');
|
|
},
|
|
get length() {
|
|
return this._length;
|
|
},
|
|
get url() {
|
|
return this._url;
|
|
}
|
|
};
|
|
function decodeMP3(soundData, ondurationchanged) {
|
|
var currentSize = 8000;
|
|
var pcm = new Float32Array(currentSize);
|
|
var position = 0;
|
|
var lastTimeRatio = 0;
|
|
var durationEstimationData = {
|
|
estimateBitRate: true,
|
|
bitRateSum: 0,
|
|
bitRateCount: 0,
|
|
metadataSize: 0,
|
|
averageBitRate: 0
|
|
};
|
|
var mp3DecoderSession = new MP3DecoderSession();
|
|
mp3DecoderSession.onframedata = function (frame, channels, sampleRate, bitRate) {
|
|
if (durationEstimationData.estimateBitRate) {
|
|
var FramesToEstimate = 200;
|
|
if (durationEstimationData.bitRateCount < FramesToEstimate) {
|
|
durationEstimationData.bitRateSum += bitRate;
|
|
durationEstimationData.bitRateCount++;
|
|
} else {
|
|
durationEstimationData.estimateBitRate = false;
|
|
}
|
|
this.averageBitRate = durationEstimationData.bitRateSum / durationEstimationData.bitRateCount;
|
|
}
|
|
if (frame.length === 0)
|
|
return;
|
|
if (!position) {
|
|
soundData.sampleRate = sampleRate, soundData.channels = channels;
|
|
soundData.pcm = pcm;
|
|
}
|
|
if (position + frame.length >= currentSize) {
|
|
do {
|
|
currentSize *= 2;
|
|
} while (position + frame.length >= currentSize);
|
|
var newPcm = new Float32Array(currentSize);
|
|
newPcm.set(pcm);
|
|
pcm = soundData.pcm = newPcm;
|
|
}
|
|
pcm.set(frame, position);
|
|
soundData.end = position += frame.length;
|
|
lastTimeRatio = 1 / soundData.sampleRate / soundData.channels;
|
|
ondurationchanged(position * lastTimeRatio, false);
|
|
};
|
|
mp3DecoderSession.onid3tag = function (data) {
|
|
durationEstimationData.metadataSize += data.length;
|
|
}, mp3DecoderSession.onclosed = function () {
|
|
ondurationchanged(position * lastTimeRatio, true);
|
|
};
|
|
var completed = false;
|
|
return {
|
|
pushData: function (data) {
|
|
mp3DecoderSession.pushAsync(data);
|
|
},
|
|
estimateDuration: function (fileSize) {
|
|
return Math.max(0, (fileSize - durationEstimationData.metadataSize) * 8 / durationEstimationData.averageBitRate);
|
|
},
|
|
close: function () {
|
|
mp3DecoderSession.close();
|
|
}
|
|
};
|
|
}
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
close: def.close,
|
|
extract: def.extract,
|
|
_load: def._load,
|
|
loadCompressedDataFromByteArray: def.loadCompressedDataFromByteArray,
|
|
loadPCMFromByteArray: def.loadPCMFromByteArray,
|
|
play: def.play,
|
|
bytesLoaded: desc(def, 'bytesLoaded'),
|
|
bytesTotal: desc(def, 'bytesTotal'),
|
|
id3: desc(def, 'id3'),
|
|
isBuffering: desc(def, 'isBuffering'),
|
|
isURLInaccessible: desc(def, 'isURLInaccessible'),
|
|
length: desc(def, 'length'),
|
|
url: desc(def, 'url')
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var SoundChannelDefinition = function () {
|
|
return {
|
|
initialize: function () {
|
|
this._element = null;
|
|
this._position = 0;
|
|
this._leftPeak = 0;
|
|
this._rightPeak = 0;
|
|
this._pcmData = null;
|
|
this._soundTransform = new flash.media.SoundTransform();
|
|
this._soundMixerClass = avm2.systemDomain.getClass('flash.media.SoundMixer');
|
|
var s = this.symbol;
|
|
if (s) {
|
|
this._element = s.element || null;
|
|
}
|
|
if (this._element) {
|
|
this._registerWithSoundMixer();
|
|
}
|
|
},
|
|
_registerWithSoundMixer: function () {
|
|
this._soundMixerClass.native.static._registerChannel(this);
|
|
},
|
|
_unregisterWithSoundMixer: function () {
|
|
this._soundMixerClass.native.static._unregisterChannel(this);
|
|
},
|
|
_applySoundTransform: function () {
|
|
var volume = this._soundTransform._volume;
|
|
if (this._soundMixerClass._soundTransform) {
|
|
volume *= this._soundMixerClass._soundTransform._volume;
|
|
}
|
|
volume *= this._soundMixerClass.native.static._getMasterVolume();
|
|
if (this._element) {
|
|
this._element.volume = clamp(volume, 0, 1);
|
|
}
|
|
if (this._audioChannel) {
|
|
}
|
|
},
|
|
_playSoundDataViaChannel: function (soundData, startTime, loops) {
|
|
this._registerWithSoundMixer();
|
|
var self = this;
|
|
var startPosition = Math.round(startTime / 1000 * soundData.sampleRate) * soundData.channels;
|
|
var position = startPosition;
|
|
this._position = startTime;
|
|
this._audioChannel = createAudioChannel(soundData.sampleRate, soundData.channels);
|
|
this._audioChannel.ondatarequested = function (e) {
|
|
var end = soundData.end;
|
|
if (position >= end && soundData.completed) {
|
|
self._unregisterWithSoundMixer();
|
|
self._audioChannel.stop();
|
|
self._dispatchEvent(new flash.events.Event('soundComplete', false, false));
|
|
return;
|
|
}
|
|
var left = e.count;
|
|
var data = e.data;
|
|
var source = soundData.pcm;
|
|
do {
|
|
var count = Math.min(end - position, left);
|
|
for (var j = 0; j < count; j++) {
|
|
data[j] = source[position++];
|
|
}
|
|
left -= count;
|
|
if (position >= end) {
|
|
if (!loops)
|
|
break;
|
|
loops--;
|
|
position = startPosition;
|
|
}
|
|
} while (left > 0);
|
|
self._position = position / soundData.sampleRate / soundData.channels * 1000;
|
|
};
|
|
this._audioChannel.start();
|
|
this._applySoundTransform();
|
|
},
|
|
_playSoundDataViaAudio: function (soundData, startTime, loops) {
|
|
if (!soundData.mimeType)
|
|
return;
|
|
this._registerWithSoundMixer();
|
|
this._position = startTime;
|
|
var self = this;
|
|
var lastCurrentTime = 0;
|
|
var element = document.createElement('audio');
|
|
if (!element.canPlayType(soundData.mimeType)) {
|
|
console.error('ERROR: "' + soundData.mimeType + '" ' + 'type playback is not supported by the browser');
|
|
return;
|
|
}
|
|
element.preload = 'metadata';
|
|
element.loop = loops > 0;
|
|
var blob = new Blob([
|
|
soundData.data
|
|
], {
|
|
type: soundData.mimeType
|
|
});
|
|
element.src = URL.createObjectURL(blob);
|
|
element.addEventListener('loadeddata', function loaded() {
|
|
element.currentTime = startTime / 1000;
|
|
element.play();
|
|
});
|
|
element.addEventListener('timeupdate', function timeupdate() {
|
|
var currentTime = element.currentTime;
|
|
if (loops && lastCurrentTime > currentTime) {
|
|
--loops;
|
|
if (!loops)
|
|
element.loop = false;
|
|
if (currentTime < startTime / 1000)
|
|
element.currentTime = startTime / 1000;
|
|
}
|
|
self._position = (lastCurrentTime = currentTime) * 1000;
|
|
});
|
|
element.addEventListener('ended', function ended() {
|
|
self._unregisterWithSoundMixer();
|
|
self._dispatchEvent(new flash.events.Event('soundComplete', false, false));
|
|
self._element = null;
|
|
});
|
|
this._element = element;
|
|
this._applySoundTransform();
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
stop: function stop() {
|
|
if (this._element) {
|
|
this._unregisterWithSoundMixer();
|
|
this._element.pause();
|
|
}
|
|
if (this._audioChannel) {
|
|
this._unregisterWithSoundMixer();
|
|
this._audioChannel.stop();
|
|
}
|
|
},
|
|
'position': {
|
|
get: function position() {
|
|
return this._position;
|
|
}
|
|
},
|
|
'leftPeak': {
|
|
get: function leftPeak() {
|
|
return this._leftPeak;
|
|
}
|
|
},
|
|
'rightPeak': {
|
|
get: function rightPeak() {
|
|
return this.rightPeak;
|
|
}
|
|
},
|
|
'soundTransform': {
|
|
get: function soundTransform() {
|
|
somewhatImplemented('SoundChannel.soundTransform');
|
|
return new flash.media.SoundTransform(this._soundTransform._volume, this._soundTransform.pan);
|
|
},
|
|
set: function soundTransform(soundTransform) {
|
|
somewhatImplemented('SoundChannel.soundTransform');
|
|
this._soundTransform = isNullOrUndefined(soundTransform) ? new flash.media.SoundTransform() : soundTransform;
|
|
this._applySoundTransform();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: scriptProperties('public', [
|
|
'stop'
|
|
])
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
function createAudioChannel(sampleRate, channels) {
|
|
if (WebAudioChannel.isSupported)
|
|
return new WebAudioChannel(sampleRate, channels);
|
|
else
|
|
error('PCM data playback is not supported by the browser');
|
|
}
|
|
function AudioResampler(sourceRate, targetRate) {
|
|
this.sourceRate = sourceRate;
|
|
this.targetRate = targetRate;
|
|
this.tail = [];
|
|
this.sourceOffset = 0;
|
|
}
|
|
AudioResampler.prototype = {
|
|
ondatarequested: function (e) {
|
|
},
|
|
getData: function (channelsData, count) {
|
|
var k = this.sourceRate / this.targetRate;
|
|
var offset = this.sourceOffset;
|
|
var needed = Math.ceil((count - 1) * k + offset) + 1;
|
|
var sourceData = [];
|
|
for (var channel = 0; channel < channelsData.length; channel++)
|
|
sourceData.push(new Float32Array(needed));
|
|
var e = {
|
|
data: sourceData,
|
|
count: needed
|
|
};
|
|
this.ondatarequested(e);
|
|
for (var channel = 0; channel < channelsData.length; channel++) {
|
|
var data = channelsData[channel];
|
|
var source = sourceData[channel];
|
|
for (var j = 0; j < count; j++) {
|
|
var i = j * k + offset;
|
|
var i1 = i | 0, i2 = Math.ceil(i) | 0;
|
|
var source_i1 = i1 < 0 ? this.tail[channel] : source[i1];
|
|
if (i1 === i2) {
|
|
data[j] = source_i1;
|
|
} else {
|
|
var alpha = i - i1;
|
|
data[j] = source_i1 * (1 - alpha) + source[i2] * alpha;
|
|
}
|
|
}
|
|
this.tail[channel] = source[needed - 1];
|
|
}
|
|
this.sourceOffset = (count - 1) * k + offset - (needed - 1);
|
|
}
|
|
};
|
|
function WebAudioChannel(sampleRate, channels) {
|
|
var context = WebAudioChannel.context;
|
|
if (!context) {
|
|
if (typeof AudioContext !== 'undefined')
|
|
context = new AudioContext();
|
|
else
|
|
context = new webkitAudioContext();
|
|
WebAudioChannel.context = context;
|
|
}
|
|
this.context = context;
|
|
this.contextSampleRate = context.sampleRate || 44100;
|
|
this.channels = channels;
|
|
this.sampleRate = sampleRate;
|
|
if (this.contextSampleRate != sampleRate) {
|
|
this.resampler = new AudioResampler(sampleRate, this.contextSampleRate);
|
|
this.resampler.ondatarequested = function (e) {
|
|
this.requestData(e.data, e.count);
|
|
}.bind(this);
|
|
}
|
|
}
|
|
WebAudioChannel.prototype = {
|
|
start: function () {
|
|
var source = this.context.createScriptProcessor ? this.context.createScriptProcessor(2048, 0, this.channels) : this.context.createJavaScriptNode(2048, 0, this.channels);
|
|
var self = this;
|
|
source.onaudioprocess = function (e) {
|
|
var channelsData = [];
|
|
for (var i = 0; i < self.channels; i++)
|
|
channelsData.push(e.outputBuffer.getChannelData(i));
|
|
var count = channelsData[0].length;
|
|
if (self.resampler) {
|
|
self.resampler.getData(channelsData, count);
|
|
} else {
|
|
var e = {
|
|
data: channelsData,
|
|
count: count
|
|
};
|
|
self.requestData(channelsData, count);
|
|
}
|
|
};
|
|
source.connect(this.context.destination);
|
|
this.source = source;
|
|
},
|
|
stop: function () {
|
|
this.source.disconnect(this.context.destination);
|
|
},
|
|
requestData: function (channelsData, count) {
|
|
var channels = this.channels;
|
|
var buffer = new Float32Array(count * channels);
|
|
var e = {
|
|
data: buffer,
|
|
count: buffer.length
|
|
};
|
|
this.ondatarequested(e);
|
|
for (var j = 0, p = 0; j < count; j++) {
|
|
for (var i = 0; i < channels; i++)
|
|
channelsData[i][j] = buffer[p++];
|
|
}
|
|
}
|
|
};
|
|
WebAudioChannel.isSupported = function () {
|
|
return typeof AudioContext !== 'undefined' || typeof webkitAudioContext != 'undefined';
|
|
}();
|
|
var SoundMixerDefinition = function () {
|
|
var masterVolume = 1;
|
|
var registeredChannels = [];
|
|
return {
|
|
__class__: 'flash.media.SoundMixer',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
_registerChannel: function _registerChannel(channel) {
|
|
registeredChannels.push(channel);
|
|
},
|
|
_unregisterChannel: function _unregisterChannel(channel) {
|
|
var index = registeredChannels.indexOf(channel);
|
|
if (index >= 0)
|
|
registeredChannels.splice(index, 1);
|
|
},
|
|
_getMasterVolume: function _getMasterVolume() {
|
|
return masterVolume;
|
|
},
|
|
_setMasterVolume: function _setMasterVolume(volume) {
|
|
masterVolume = volume;
|
|
registeredChannels.forEach(function (channel) {
|
|
channel._applySoundTransform();
|
|
});
|
|
},
|
|
stopAll: function stopAll() {
|
|
registeredChannels.forEach(function (channel) {
|
|
channel.stop();
|
|
});
|
|
registeredChannels = [];
|
|
},
|
|
computeSpectrum: function computeSpectrum(outputArray, FFTMode, stretchFactor) {
|
|
somewhatImplemented('SoundMixer.computeSpectrum');
|
|
var data = new Float32Array(1024);
|
|
for (var i = 0; i < 1024; i++) {
|
|
data[i] = Math.random();
|
|
}
|
|
outputArray.writeRawBytes(data);
|
|
outputArray.position = 0;
|
|
},
|
|
areSoundsInaccessible: function areSoundsInaccessible() {
|
|
notImplemented('SoundMixer.areSoundsInaccessible');
|
|
},
|
|
bufferTime: {
|
|
get: function bufferTime() {
|
|
notImplemented('SoundMixer.bufferTime');
|
|
},
|
|
set: function bufferTime(pA) {
|
|
notImplemented('SoundMixer.bufferTime');
|
|
}
|
|
},
|
|
soundTransform: {
|
|
get: function soundTransform() {
|
|
somewhatImplemented('SoundMixer.soundTransform');
|
|
return isNullOrUndefined(this._soundTransform) ? new flash.media.SoundTransform() : new flash.media.SoundTransform(this._soundTransform._volume, this._soundTransform.pan);
|
|
},
|
|
set: function soundTransform(soundTransform) {
|
|
somewhatImplemented('SoundMixer.soundTransform');
|
|
this._soundTransform = isNullOrUndefined(soundTransform) ? new flash.media.SoundTransform() : soundTransform;
|
|
registeredChannels.forEach(function (channel) {
|
|
channel._applySoundTransform();
|
|
});
|
|
}
|
|
},
|
|
audioPlaybackMode: {
|
|
get: function audioPlaybackMode() {
|
|
notImplemented('SoundMixer.audioPlaybackMode');
|
|
},
|
|
set: function audioPlaybackMode(pA) {
|
|
notImplemented('SoundMixer.audioPlaybackMode');
|
|
}
|
|
},
|
|
useSpeakerphoneForVoice: {
|
|
get: function useSpeakerphoneForVoice() {
|
|
notImplemented('SoundMixer.useSpeakerphoneForVoice');
|
|
},
|
|
set: function useSpeakerphoneForVoice(pA) {
|
|
notImplemented('SoundMixer.useSpeakerphoneForVoice');
|
|
}
|
|
}
|
|
},
|
|
instance: {}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var SoundTransformDefinition = function () {
|
|
return {
|
|
__class__: 'flash.media.SoundTransform',
|
|
initialize: function () {
|
|
},
|
|
_updateTransform: function () {
|
|
somewhatImplemented('SoundTransform._updateTransform');
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
volume: {
|
|
get: function volume() {
|
|
return this._volume;
|
|
},
|
|
set: function volume(volume) {
|
|
this._volume = volume;
|
|
this._updateTransform();
|
|
}
|
|
},
|
|
leftToLeft: {
|
|
get: function leftToLeft() {
|
|
return this._leftToLeft;
|
|
},
|
|
set: function leftToLeft(leftToLeft) {
|
|
this._leftToLeft = leftToLeft;
|
|
this._updateTransform();
|
|
}
|
|
},
|
|
leftToRight: {
|
|
get: function leftToRight() {
|
|
return this._leftToRight;
|
|
},
|
|
set: function leftToRight(leftToRight) {
|
|
this._leftToRight = leftToRight;
|
|
this._updateTransform();
|
|
}
|
|
},
|
|
rightToRight: {
|
|
get: function rightToRight() {
|
|
return this._rightToRight;
|
|
},
|
|
set: function rightToRight(rightToRight) {
|
|
this._rightToRight = rightToRight;
|
|
this._updateTransform();
|
|
}
|
|
},
|
|
rightToLeft: {
|
|
get: function rightToLeft() {
|
|
return this._rightToLeft;
|
|
},
|
|
set: function rightToLeft(rightToLeft) {
|
|
this._rightToLeft = rightToLeft;
|
|
this._updateTransform();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: {
|
|
pan: 'public pan'
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var StageVideoDefinition = function () {
|
|
return {
|
|
__class__: 'flash.media.StageVideo',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
attachNetStream: function attachNetStream(netStream) {
|
|
notImplemented('StageVideo.attachNetStream');
|
|
},
|
|
attachCamera: function attachCamera(theCamera) {
|
|
notImplemented('StageVideo.attachCamera');
|
|
},
|
|
viewPort: {
|
|
get: function viewPort() {
|
|
notImplemented('StageVideo.viewPort');
|
|
return this._viewPort;
|
|
},
|
|
set: function viewPort(rect) {
|
|
notImplemented('StageVideo.viewPort');
|
|
this._viewPort = rect;
|
|
}
|
|
},
|
|
pan: {
|
|
set: function pan(point) {
|
|
notImplemented('StageVideo.pan');
|
|
this._pan = point;
|
|
},
|
|
get: function pan() {
|
|
notImplemented('StageVideo.pan');
|
|
return this._pan;
|
|
}
|
|
},
|
|
zoom: {
|
|
set: function zoom(point) {
|
|
notImplemented('StageVideo.zoom');
|
|
this._zoom = point;
|
|
},
|
|
get: function zoom() {
|
|
notImplemented('StageVideo.zoom');
|
|
return this._zoom;
|
|
}
|
|
},
|
|
depth: {
|
|
set: function depth(depth) {
|
|
notImplemented('StageVideo.depth');
|
|
this._depth = depth;
|
|
},
|
|
get: function depth() {
|
|
notImplemented('StageVideo.depth');
|
|
return this._depth;
|
|
}
|
|
},
|
|
videoWidth: {
|
|
get: function videoWidth() {
|
|
notImplemented('StageVideo.videoWidth');
|
|
return this._videoWidth;
|
|
}
|
|
},
|
|
videoHeight: {
|
|
get: function videoHeight() {
|
|
notImplemented('StageVideo.videoHeight');
|
|
return this._videoHeight;
|
|
}
|
|
},
|
|
colorSpaces: {
|
|
get: function colorSpaces() {
|
|
notImplemented('StageVideo.colorSpaces');
|
|
return this._colorSpaces;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var VideoDefinition = function () {
|
|
function burnHole(ctx, x, y, width, height) {
|
|
ctx.save();
|
|
ctx.beginPath();
|
|
ctx.rect(0, 0, width, height);
|
|
ctx.clip();
|
|
ctx.clearRect(0, 0, width, height);
|
|
ctx.restore();
|
|
}
|
|
var def = {
|
|
initialize: function initialize() {
|
|
TelemetryService.reportTelemetry({
|
|
topic: 'feature',
|
|
feature: VIDEO_FEATURE
|
|
});
|
|
},
|
|
attachNetStream: function (netStream) {
|
|
if (this._netStream === netStream) {
|
|
return;
|
|
}
|
|
if (this._netStream) {
|
|
this._netStream._videoReady.then(function (element) {
|
|
this._element = null;
|
|
if (this._added) {
|
|
element.remove();
|
|
this._added = false;
|
|
}
|
|
}.bind(this));
|
|
}
|
|
this._netStream = netStream;
|
|
if (!netStream) {
|
|
return;
|
|
}
|
|
netStream._videoReady.then(function (element) {
|
|
this._element = element;
|
|
netStream._videoMetadataReady.then(function (url) {
|
|
this._element.width = this._videoWidth = this._element.videoWidth;
|
|
this._element.height = this._videoHeight = this._element.videoHeight;
|
|
if (this.stage) {
|
|
this.stage._invalid = true;
|
|
}
|
|
}.bind(this));
|
|
}.bind(this));
|
|
},
|
|
ctor: function (width, height) {
|
|
if (!width || width < 0)
|
|
width = 320;
|
|
if (!height || height < 0)
|
|
height = 240;
|
|
this._bbox = {
|
|
xMin: 0,
|
|
yMin: 0,
|
|
xMax: width * 20,
|
|
yMax: height * 20
|
|
};
|
|
this._initialWidth = this._videoWidth = width;
|
|
this._initialHeight = this._videoHeight = height;
|
|
this._netStream = null;
|
|
this._element = null;
|
|
this._added = false;
|
|
},
|
|
draw: function (ctx, ratio, ct, parentCtxs) {
|
|
if (!this._element) {
|
|
return;
|
|
}
|
|
if (!this._added && this._stage) {
|
|
this._stage._domContainer.appendChild(this._element);
|
|
this._added = true;
|
|
}
|
|
var width = this._initialWidth;
|
|
var height = this._initialHeight;
|
|
var matrix = this._getConcatenatedTransform(null, true);
|
|
var scaleFactor = this.stage && this.stage._contentsScaleFactor || 1;
|
|
var a = matrix.a / scaleFactor;
|
|
var b = matrix.b / scaleFactor;
|
|
var c = matrix.c / scaleFactor;
|
|
var d = matrix.d / scaleFactor;
|
|
var e = matrix.tx / 20 / scaleFactor;
|
|
var f = matrix.ty / 20 / scaleFactor;
|
|
if (width > 0 && height > 0) {
|
|
burnHole(ctx, 0, 0, width, height);
|
|
parentCtxs.forEach(function (ctx) {
|
|
ctx.save();
|
|
ctx.setTransform(a, b, c, d, e, f);
|
|
burnHole(ctx, 0, 0, width, height);
|
|
ctx.restore();
|
|
});
|
|
}
|
|
var sx = width / this._videoWidth;
|
|
var sy = height / this._videoHeight;
|
|
var cssTransform = 'transform: matrix(' + sx * a + ',' + sx * b + ',' + sy * c + ',' + sy * d + ',' + e + ',' + f + ');';
|
|
if (this._currentCssTransform !== cssTransform) {
|
|
this._currentCssTransform = cssTransform;
|
|
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);
|
|
}
|
|
}
|
|
};
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
attachNetStream: def.attachNetStream,
|
|
ctor: def.ctor,
|
|
smoothing: {
|
|
get: function smoothing() {
|
|
return this._smoothing;
|
|
},
|
|
set: function smoothing(value) {
|
|
somewhatImplemented('Video.smoothing');
|
|
this._smoothing = value;
|
|
}
|
|
},
|
|
videoHeight: {
|
|
get: function videoHeight() {
|
|
return this._videoHeight;
|
|
}
|
|
},
|
|
videoWidth: {
|
|
get: function videoWidth() {
|
|
return this._videoWidth;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
{
|
|
var FileFilterDefinition = function () {
|
|
return {
|
|
__class__: 'flash.net.FileFilter',
|
|
initialize: function () {
|
|
this._description = null;
|
|
this._extension = null;
|
|
this._macType = null;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
description: {
|
|
get: function description() {
|
|
return this._description;
|
|
},
|
|
set: function description(value) {
|
|
this._description = value;
|
|
}
|
|
},
|
|
extension: {
|
|
get: function extension() {
|
|
return this._extension;
|
|
},
|
|
set: function extension(value) {
|
|
this._extension = value;
|
|
}
|
|
},
|
|
macType: {
|
|
get: function macType() {
|
|
return this._macType;
|
|
},
|
|
set: function macType(value) {
|
|
this._macType = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
}
|
|
var LocalConnectionDefinition = function () {
|
|
return {
|
|
__class__: 'flash.net.LocalConnection',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
close: function close() {
|
|
notImplemented('LocalConnection.close');
|
|
},
|
|
connect: function connect(connectionName) {
|
|
notImplemented('LocalConnection.connect');
|
|
},
|
|
send: function send(connectionName, methodName) {
|
|
notImplemented('LocalConnection.send');
|
|
},
|
|
allowDomain: function allowDomain() {
|
|
notImplemented('LocalConnection.allowDomain');
|
|
},
|
|
allowInsecureDomain: function allowInsecureDomain() {
|
|
notImplemented('LocalConnection.allowInsecureDomain');
|
|
},
|
|
domain: {
|
|
get: function domain() {
|
|
somewhatImplemented('LocalConnection.domain');
|
|
var url = FileLoadingService.resolveUrl('/');
|
|
var m = /:\/\/(.+?)[:?#\/]/.exec(url);
|
|
return m && m[1];
|
|
}
|
|
},
|
|
client: {
|
|
get: function client() {
|
|
notImplemented('LocalConnection.client');
|
|
return this._client;
|
|
},
|
|
set: function client(client) {
|
|
notImplemented('LocalConnection.client');
|
|
this._client = client;
|
|
}
|
|
},
|
|
isPerUser: {
|
|
get: function isPerUser() {
|
|
notImplemented('LocalConnection.isPerUser');
|
|
return this._isPerUser;
|
|
},
|
|
set: function isPerUser(newValue) {
|
|
notImplemented('LocalConnection.isPerUser');
|
|
this._isPerUser = newValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var NetConnectionDefinition = function () {
|
|
var defaultObjectEncoding = 3;
|
|
return {
|
|
__class__: 'flash.net.NetConnection',
|
|
initialize: function () {
|
|
TelemetryService.reportTelemetry({
|
|
topic: 'feature',
|
|
feature: NETCONNECTION_FEATURE
|
|
});
|
|
},
|
|
_invoke: function (index, args) {
|
|
var simulated = false, result;
|
|
switch (index) {
|
|
case 2:
|
|
simulated = true;
|
|
break;
|
|
}
|
|
(simulated ? somewhatImplemented : notImplemented)('NetConnection._invoke (' + index + ')');
|
|
return result;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
defaultObjectEncoding: {
|
|
get: function defaultObjectEncoding() {
|
|
return defaultObjectEncoding;
|
|
},
|
|
set: function defaultObjectEncoding(version) {
|
|
somewhatImplemented('NetConnection.defaultObjectEncoding');
|
|
return defaultObjectEncoding;
|
|
}
|
|
}
|
|
},
|
|
instance: {
|
|
ctor: function ctor() {
|
|
this._uri = null;
|
|
this._connected = false;
|
|
this._client = null;
|
|
this._proxyType = 'none';
|
|
this._objectEncoding = defaultObjectEncoding;
|
|
},
|
|
connect: function connect(command) {
|
|
var NetStatusEvent = flash.events.NetStatusEvent;
|
|
somewhatImplemented('NetConnection.connect');
|
|
this._uri = command;
|
|
if (!command) {
|
|
this._connected = true;
|
|
this._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({
|
|
level: 'status',
|
|
code: 'NetConnection.Connect.Success'
|
|
})));
|
|
} else {
|
|
this._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({
|
|
level: 'status',
|
|
code: 'NetConnection.Connect.Failed'
|
|
})));
|
|
}
|
|
},
|
|
call: function call(command, responder) {
|
|
notImplemented('NetConnection.call');
|
|
},
|
|
connected: {
|
|
get: function connected() {
|
|
return this._connected;
|
|
}
|
|
},
|
|
uri: {
|
|
get: function uri() {
|
|
return this._uri;
|
|
}
|
|
},
|
|
client: {
|
|
get: function client() {
|
|
return this._client;
|
|
},
|
|
set: function client(object) {
|
|
this._client = object;
|
|
}
|
|
},
|
|
objectEncoding: {
|
|
get: function objectEncoding() {
|
|
return this._objectEncoding;
|
|
},
|
|
set: function objectEncoding(version) {
|
|
somewhatImplemented('NetConnection.objectEncoding');
|
|
this._objectEncoding = version;
|
|
}
|
|
},
|
|
proxyType: {
|
|
get: function proxyType() {
|
|
return this._proxyType;
|
|
},
|
|
set: function proxyType(ptype) {
|
|
notImplemented('NetConnection.proxyType');
|
|
this._proxyType = ptype;
|
|
}
|
|
},
|
|
connectedProxyType: {
|
|
get: function connectedProxyType() {
|
|
notImplemented('NetConnection.connectedProxyType');
|
|
return this._connectedProxyType;
|
|
}
|
|
},
|
|
usingTLS: {
|
|
get: function usingTLS() {
|
|
somewhatImplemented('NetConnection.usingTLS');
|
|
return false;
|
|
}
|
|
},
|
|
protocol: {
|
|
get: function protocol() {
|
|
notImplemented('NetConnection.protocol');
|
|
return this._protocol;
|
|
}
|
|
},
|
|
maxPeerConnections: {
|
|
get: function maxPeerConnections() {
|
|
notImplemented('NetConnection.maxPeerConnections');
|
|
return this._maxPeerConnections;
|
|
},
|
|
set: function maxPeerConnections(maxPeers) {
|
|
notImplemented('NetConnection.maxPeerConnections');
|
|
this._maxPeerConnections = maxPeers;
|
|
}
|
|
},
|
|
nearID: {
|
|
get: function nearID() {
|
|
notImplemented('NetConnection.nearID');
|
|
return this._nearID;
|
|
}
|
|
},
|
|
farID: {
|
|
get: function farID() {
|
|
notImplemented('NetConnection.farID');
|
|
return this._farID;
|
|
}
|
|
},
|
|
nearNonce: {
|
|
get: function nearNonce() {
|
|
notImplemented('NetConnection.nearNonce');
|
|
return this._nearNonce;
|
|
}
|
|
},
|
|
farNonce: {
|
|
get: function farNonce() {
|
|
notImplemented('NetConnection.farNonce');
|
|
return this._farNonce;
|
|
}
|
|
},
|
|
unconnectedPeerStreams: {
|
|
get: function unconnectedPeerStreams() {
|
|
notImplemented('NetConnection.unconnectedPeerStreams');
|
|
return this._unconnectedPeerStreams;
|
|
}
|
|
},
|
|
invoke: function invokeWithArgsArray(index) {
|
|
return this._invoke(index, Array.prototype.slice.call(arguments, 1));
|
|
},
|
|
invokeWithArgsArray: function invokeWithArgsArray(index, p_arguments) {
|
|
return this._invoke.call(this, index, p_arguments);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var USE_MEDIASOURCE_API = false;
|
|
var NetStreamDefinition = function () {
|
|
return {
|
|
__class__: 'flash.net.NetStream',
|
|
initialize: function () {
|
|
},
|
|
_invoke: function (index, args) {
|
|
var simulated = false, result;
|
|
var videoElement = this._videoElement;
|
|
switch (index) {
|
|
case 4:
|
|
this._videoState.bufferTime = args[0];
|
|
simulated = true;
|
|
break;
|
|
case 202:
|
|
switch (args[1]) {
|
|
case 'pause':
|
|
simulated = true;
|
|
if (videoElement) {
|
|
if (args[3] !== false && !videoElement.paused) {
|
|
videoElement.pause();
|
|
} else if (args[3] !== true && videoElement.paused) {
|
|
videoElement.play();
|
|
}
|
|
videoElement.currentTime = args[4] / 1000;
|
|
}
|
|
break;
|
|
case 'seek':
|
|
simulated = true;
|
|
if (videoElement && !videoElement.paused) {
|
|
videoElement.currentTime = args[3] / 1000;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 300:
|
|
result = videoElement ? videoElement.currentTime : 0;
|
|
simulated = true;
|
|
break;
|
|
case 302:
|
|
result = this._videoState.bufferTime;
|
|
simulated = true;
|
|
break;
|
|
case 303:
|
|
result = videoElement ? videoElement.duration : 0;
|
|
simulated = true;
|
|
break;
|
|
case 305:
|
|
result = this._videoState.buffer === 'full' ? 100 : this._videoState.buffer === 'progress' ? 50 : 0;
|
|
simulated = true;
|
|
break;
|
|
case 306:
|
|
result = 100;
|
|
simulated = true;
|
|
break;
|
|
}
|
|
(simulated ? somewhatImplemented : notImplemented)('NetStream._invoke (' + index + ')');
|
|
return result;
|
|
},
|
|
_createVideoElement: function (url) {
|
|
function notifyPlayStart(e) {
|
|
if (netStream._videoState.started) {
|
|
return;
|
|
}
|
|
netStream._videoState.started = true;
|
|
netStream._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({
|
|
code: 'NetStream.Play.Start',
|
|
level: 'status'
|
|
})));
|
|
}
|
|
function notifyPlayStop(e) {
|
|
netStream._videoState.started = false;
|
|
netStream._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({
|
|
code: 'NetStream.Play.Stop',
|
|
level: 'status'
|
|
})));
|
|
}
|
|
function notifyBufferFull(e) {
|
|
netStream._videoState.buffer = 'full';
|
|
netStream._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({
|
|
code: 'NetStream.Buffer.Full',
|
|
level: 'status'
|
|
})));
|
|
}
|
|
function notifyProgress(e) {
|
|
netStream._videoState.buffer = 'progress';
|
|
}
|
|
function notifyBufferEmpty(e) {
|
|
netStream._videoState.buffer = 'empty';
|
|
netStream._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({
|
|
code: 'NetStream.Buffer.Empty',
|
|
level: 'status'
|
|
})));
|
|
}
|
|
function notifyError(e) {
|
|
var code = e.target.error.code === 4 ? 'NetStream.Play.NoSupportedTrackFound' : e.target.error.code === 3 ? 'NetStream.Play.FileStructureInvalid' : 'NetStream.Play.StreamNotFound';
|
|
netStream._dispatchEvent(new NetStatusEvent(NetStatusEvent.class.NET_STATUS, false, false, wrapJSObject({
|
|
code: code,
|
|
level: 'error'
|
|
})));
|
|
}
|
|
function notifyMetadata(e) {
|
|
netStream._videoMetadataReady.resolve({
|
|
videoWidth: element.videoWidth,
|
|
videoHeight: element.videoHeight
|
|
});
|
|
if (netStream._client) {
|
|
var data = {};
|
|
data.asSetPublicProperty('width', element.videoWidth);
|
|
data.asSetPublicProperty('height', element.videoHeight);
|
|
data.asSetPublicProperty('duration', element.duration);
|
|
netStream._client.asCallPublicProperty('onMetaData', [
|
|
data
|
|
]);
|
|
}
|
|
}
|
|
var NetStatusEvent = flash.events.NetStatusEvent;
|
|
var netStream = this;
|
|
if (/\.mp4$/i.test(url) && /Intel Mac OS X.*?Firefox\/\d+/.test(window.navigator.userAgent)) {
|
|
url = 'http://videos-cdn.mozilla.net/brand/Mozilla_2011_Story.webm';
|
|
}
|
|
var element = document.createElement('video');
|
|
element.preload = 'metadata';
|
|
element.src = url;
|
|
element.addEventListener('play', notifyPlayStart);
|
|
element.addEventListener('ended', notifyPlayStop);
|
|
element.addEventListener('loadeddata', notifyBufferFull);
|
|
element.addEventListener('progress', notifyProgress);
|
|
element.addEventListener('waiting', notifyBufferEmpty);
|
|
element.addEventListener('loadedmetadata', notifyMetadata);
|
|
element.addEventListener('error', notifyError);
|
|
element.play();
|
|
this._videoElement = element;
|
|
this._videoReady.resolve(element);
|
|
},
|
|
__glue__: {
|
|
script: {
|
|
instance: scriptProperties('public', [
|
|
'appendBytes',
|
|
'appendBytesAction'
|
|
])
|
|
},
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
ctor: function ctor(connection, peerID) {
|
|
somewhatImplemented('NetStream.ctor');
|
|
this._contentTypeHint = null;
|
|
this._mediaSource = null;
|
|
this._checkPolicyFile = true;
|
|
this._videoElement = null;
|
|
var videoReadyResolve, videoReadyReject;
|
|
this._videoReady = new Promise(function (resolve, reject) {
|
|
videoReadyResolve = resolve;
|
|
videoReadyReject = reject;
|
|
});
|
|
this._videoReady.resolve = videoReadyResolve;
|
|
this._videoReady.reject = videoReadyReject;
|
|
var videoMetadataReadyResolve, videoMetadataReadyReject;
|
|
this._videoMetadataReady = new Promise(function (resolve, reject) {
|
|
videoMetadataReadyResolve = resolve;
|
|
videoMetadataReadyReject = reject;
|
|
});
|
|
this._videoMetadataReady.resolve = videoMetadataReadyResolve;
|
|
this._videoMetadataReady.reject = videoMetadataReadyReject;
|
|
this._videoState = {
|
|
started: false,
|
|
buffer: 'empty',
|
|
bufferTime: 0.1
|
|
};
|
|
},
|
|
onResult: function onResult(streamId) {
|
|
notImplemented('NetStream.onResult');
|
|
},
|
|
dispose: function dispose() {
|
|
notImplemented('NetStream.dispose');
|
|
},
|
|
play: function play(url) {
|
|
var isMediaSourceEnabled = USE_MEDIASOURCE_API;
|
|
if (isMediaSourceEnabled && typeof MediaSource === 'undefined') {
|
|
console.warn('MediaSource API is not enabled, falling back to regular playback');
|
|
isMediaSourceEnabled = false;
|
|
}
|
|
if (!isMediaSourceEnabled) {
|
|
somewhatImplemented('NetStream.play');
|
|
this._createVideoElement(FileLoadingService.resolveUrl(url));
|
|
return;
|
|
}
|
|
var mediaSource = new MediaSource();
|
|
mediaSource.addEventListener('sourceopen', function (e) {
|
|
this._mediaSource = mediaSource;
|
|
}.bind(this));
|
|
mediaSource.addEventListener('sourceend', function (e) {
|
|
this._mediaSource = null;
|
|
}.bind(this));
|
|
this._createVideoElement(window.URL.createObjectURL(mediaSource));
|
|
if (!url) {
|
|
return;
|
|
}
|
|
var request = new flash.net.URLRequest(url);
|
|
request._checkPolicyFile = this._checkPolicyFile;
|
|
var stream = new flash.net.URLStream();
|
|
stream._addEventListener('httpStatus', function (e) {
|
|
var responseHeaders = e.asGetPublicProperty('responseHeaders');
|
|
var contentTypeHeader = responseHeaders.filter(function (h) {
|
|
return h.asGetPublicProperty('name') === 'Content-Type';
|
|
})[0];
|
|
if (contentTypeHeader && contentTypeHeader.asGetPublicProperty('value') !== 'application/octet-stream') {
|
|
this._contentTypeHint = contentTypeHeader.asGetPublicProperty('value');
|
|
}
|
|
}.bind(this));
|
|
stream._addEventListener('progress', function (e) {
|
|
var available = stream.bytesAvailable;
|
|
var ByteArrayClass = avm2.systemDomain.getClass('flash.utils.ByteArray');
|
|
var data = ByteArrayClass.createInstance();
|
|
stream.readBytes(data, 0, available);
|
|
this.appendBytes(data);
|
|
}.bind(this));
|
|
stream._addEventListener('complete', function (e) {
|
|
this.appendBytesAction('endSequence');
|
|
}.bind(this));
|
|
stream.load(request);
|
|
},
|
|
play2: function play2(param) {
|
|
notImplemented('NetStream.play2');
|
|
},
|
|
invoke: function invoke(index) {
|
|
return this._invoke(index, Array.prototype.slice.call(arguments, 1));
|
|
},
|
|
invokeWithArgsArray: function invokeWithArgsArray(index, p_arguments) {
|
|
return this._invoke.call(this, index, p_arguments);
|
|
},
|
|
appendBytes: function appendBytes(bytes) {
|
|
if (this._mediaSource) {
|
|
if (!this._mediaSourceBuffer) {
|
|
this._mediaSourceBuffer = this._mediaSource.addSourceBuffer(this._contentTypeHint);
|
|
}
|
|
this._mediaSourceBuffer.appendBuffer(new Uint8Array(bytes.a, 0, bytes.length));
|
|
}
|
|
somewhatImplemented('NetStream.appendBytes');
|
|
},
|
|
appendBytesAction: function appendBytesAction(netStreamAppendBytesAction) {
|
|
if (netStreamAppendBytesAction === 'endSequence' && this._mediaSource) {
|
|
this._mediaSource.endOfStream();
|
|
}
|
|
somewhatImplemented('NetStream.appendBytesAction');
|
|
},
|
|
info: {
|
|
get: function info() {
|
|
notImplemented('NetStream.info');
|
|
return this._info;
|
|
}
|
|
},
|
|
multicastInfo: {
|
|
get: function multicastInfo() {
|
|
notImplemented('NetStream.multicastInfo');
|
|
return this._multicastInfo;
|
|
}
|
|
},
|
|
soundTransform: {
|
|
get: function soundTransform() {
|
|
return this._soundTransform;
|
|
},
|
|
set: function soundTransform(sndTransform) {
|
|
somewhatImplemented('NetStream.soundTransform');
|
|
this._soundTransform = sndTransform;
|
|
}
|
|
},
|
|
checkPolicyFile: {
|
|
get: function checkPolicyFile() {
|
|
return this._checkPolicyFile;
|
|
},
|
|
set: function checkPolicyFile(state) {
|
|
this._checkPolicyFile = state;
|
|
}
|
|
},
|
|
client: {
|
|
get: function client() {
|
|
somewhatImplemented('NetStream.client');
|
|
return this._client;
|
|
},
|
|
set: function client(object) {
|
|
somewhatImplemented('NetStream.client');
|
|
this._client = object;
|
|
}
|
|
},
|
|
objectEncoding: {
|
|
get: function objectEncoding() {
|
|
notImplemented('NetStream.objectEncoding');
|
|
return this._objectEncoding;
|
|
}
|
|
},
|
|
multicastPushNeighborLimit: {
|
|
get: function multicastPushNeighborLimit() {
|
|
notImplemented('NetStream.multicastPushNeighborLimit');
|
|
return this._multicastPushNeighborLimit;
|
|
},
|
|
set: function multicastPushNeighborLimit(neighbors) {
|
|
notImplemented('NetStream.multicastPushNeighborLimit');
|
|
this._multicastPushNeighborLimit = neighbors;
|
|
}
|
|
},
|
|
multicastWindowDuration: {
|
|
get: function multicastWindowDuration() {
|
|
notImplemented('NetStream.multicastWindowDuration');
|
|
return this._multicastWindowDuration;
|
|
},
|
|
set: function multicastWindowDuration(seconds) {
|
|
notImplemented('NetStream.multicastWindowDuration');
|
|
this._multicastWindowDuration = seconds;
|
|
}
|
|
},
|
|
multicastRelayMarginDuration: {
|
|
get: function multicastRelayMarginDuration() {
|
|
notImplemented('NetStream.multicastRelayMarginDuration');
|
|
return this._multicastRelayMarginDuration;
|
|
},
|
|
set: function multicastRelayMarginDuration(seconds) {
|
|
notImplemented('NetStream.multicastRelayMarginDuration');
|
|
this._multicastRelayMarginDuration = seconds;
|
|
}
|
|
},
|
|
multicastAvailabilityUpdatePeriod: {
|
|
get: function multicastAvailabilityUpdatePeriod() {
|
|
notImplemented('NetStream.multicastAvailabilityUpdatePeriod');
|
|
return this._multicastAvailabilityUpdatePeriod;
|
|
},
|
|
set: function multicastAvailabilityUpdatePeriod(seconds) {
|
|
notImplemented('NetStream.multicastAvailabilityUpdatePeriod');
|
|
this._multicastAvailabilityUpdatePeriod = seconds;
|
|
}
|
|
},
|
|
multicastFetchPeriod: {
|
|
get: function multicastFetchPeriod() {
|
|
notImplemented('NetStream.multicastFetchPeriod');
|
|
return this._multicastFetchPeriod;
|
|
},
|
|
set: function multicastFetchPeriod(seconds) {
|
|
notImplemented('NetStream.multicastFetchPeriod');
|
|
this._multicastFetchPeriod = seconds;
|
|
}
|
|
},
|
|
multicastAvailabilitySendToAll: {
|
|
get: function multicastAvailabilitySendToAll() {
|
|
notImplemented('NetStream.multicastAvailabilitySendToAll');
|
|
return this._multicastAvailabilitySendToAll;
|
|
},
|
|
set: function multicastAvailabilitySendToAll(value) {
|
|
notImplemented('NetStream.multicastAvailabilitySendToAll');
|
|
this._multicastAvailabilitySendToAll = value;
|
|
}
|
|
},
|
|
farID: {
|
|
get: function farID() {
|
|
notImplemented('NetStream.farID');
|
|
return this._farID;
|
|
}
|
|
},
|
|
nearNonce: {
|
|
get: function nearNonce() {
|
|
notImplemented('NetStream.nearNonce');
|
|
return this._nearNonce;
|
|
}
|
|
},
|
|
farNonce: {
|
|
get: function farNonce() {
|
|
notImplemented('NetStream.farNonce');
|
|
return this._farNonce;
|
|
}
|
|
},
|
|
peerStreams: {
|
|
get: function peerStreams() {
|
|
notImplemented('NetStream.peerStreams');
|
|
return this._peerStreams;
|
|
}
|
|
},
|
|
audioReliable: {
|
|
get: function audioReliable() {
|
|
notImplemented('NetStream.audioReliable');
|
|
return this._audioReliable;
|
|
},
|
|
set: function audioReliable(reliable) {
|
|
notImplemented('NetStream.audioReliable');
|
|
this._audioReliable = reliable;
|
|
}
|
|
},
|
|
videoReliable: {
|
|
get: function videoReliable() {
|
|
notImplemented('NetStream.videoReliable');
|
|
return this._videoReliable;
|
|
},
|
|
set: function videoReliable(reliable) {
|
|
notImplemented('NetStream.videoReliable');
|
|
this._videoReliable = reliable;
|
|
}
|
|
},
|
|
dataReliable: {
|
|
get: function dataReliable() {
|
|
notImplemented('NetStream.dataReliable');
|
|
return this._dataReliable;
|
|
},
|
|
set: function dataReliable(reliable) {
|
|
notImplemented('NetStream.dataReliable');
|
|
this._dataReliable = reliable;
|
|
}
|
|
},
|
|
audioSampleAccess: {
|
|
get: function audioSampleAccess() {
|
|
notImplemented('NetStream.audioSampleAccess');
|
|
return this._audioSampleAccess;
|
|
},
|
|
set: function audioSampleAccess(reliable) {
|
|
notImplemented('NetStream.audioSampleAccess');
|
|
this._audioSampleAccess = reliable;
|
|
}
|
|
},
|
|
videoSampleAccess: {
|
|
get: function videoSampleAccess() {
|
|
notImplemented('NetStream.videoSampleAccess');
|
|
return this._videoSampleAccess;
|
|
},
|
|
set: function videoSampleAccess(reliable) {
|
|
notImplemented('NetStream.videoSampleAccess');
|
|
this._videoSampleAccess = reliable;
|
|
}
|
|
},
|
|
useHardwareDecoder: {
|
|
get: function useHardwareDecoder() {
|
|
notImplemented('NetStream.useHardwareDecoder');
|
|
return this._useHardwareDecoder;
|
|
},
|
|
set: function useHardwareDecoder(v) {
|
|
notImplemented('NetStream.useHardwareDecoder');
|
|
this._useHardwareDecoder = v;
|
|
}
|
|
},
|
|
useJitterBuffer: {
|
|
get: function useJitterBuffer() {
|
|
notImplemented('NetStream.useJitterBuffer');
|
|
return this._useJitterBuffer;
|
|
},
|
|
set: function useJitterBuffer(value) {
|
|
notImplemented('NetStream.useJitterBuffer');
|
|
this._useJitterBuffer = value;
|
|
}
|
|
},
|
|
videoStreamSettings: {
|
|
get: function videoStreamSettings() {
|
|
notImplemented('NetStream.videoStreamSettings');
|
|
return this._videoStreamSettings;
|
|
},
|
|
set: function videoStreamSettings(settings) {
|
|
notImplemented('NetStream.videoStreamSettings');
|
|
this._videoStreamSettings = settings;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var ObjectEncodingDefinition = function () {
|
|
return {
|
|
__class__: 'flash.net.ObjectEncoding',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
dynamicPropertyWriter: {
|
|
get: function dynamicPropertyWriter() {
|
|
notImplemented('ObjectEncoding.dynamicPropertyWriter');
|
|
},
|
|
set: function dynamicPropertyWriter(object) {
|
|
notImplemented('ObjectEncoding.dynamicPropertyWriter');
|
|
}
|
|
}
|
|
},
|
|
instance: {}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var ResponderDefinition = function () {
|
|
var def = {
|
|
ctor: function (result, status) {
|
|
}
|
|
};
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
ctor: def.ctor
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var SharedObjectDefinition = function () {
|
|
var _defaultObjectEncoding = 3;
|
|
var sharedObjects = createEmptyObject();
|
|
function invokeWithArgsArray(index, args) {
|
|
var simulated = false, result;
|
|
switch (index) {
|
|
case 4:
|
|
result = JSON.stringify(this._data).length - 2;
|
|
simulated = true;
|
|
break;
|
|
case 6:
|
|
this._data = {};
|
|
sessionStorage.removeItem(this._path);
|
|
simulated = true;
|
|
break;
|
|
case 2:
|
|
sessionStorage.setItem(this._path, JSON.stringify(this._data));
|
|
simulated = true;
|
|
result = true;
|
|
break;
|
|
case 3:
|
|
simulated = true;
|
|
break;
|
|
}
|
|
(simulated ? somewhatImplemented : notImplemented)('SharedObject.invoke (' + index + ')');
|
|
return result;
|
|
}
|
|
return {
|
|
__class__: 'flash.net.SharedObject',
|
|
initialize: function () {
|
|
this._path = null;
|
|
this._data = null;
|
|
this._objectEncoding = _defaultObjectEncoding;
|
|
TelemetryService.reportTelemetry({
|
|
topic: 'feature',
|
|
feature: SHAREDOBJECT_FEATURE
|
|
});
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
deleteAll: function deleteAll(url) {
|
|
notImplemented('SharedObject.deleteAll');
|
|
},
|
|
getDiskUsage: function getDiskUsage(url) {
|
|
notImplemented('SharedObject.getDiskUsage');
|
|
},
|
|
getLocal: function getLocal(name, localPath, secure) {
|
|
var path = (localPath || '') + '/' + name;
|
|
if (sharedObjects[path]) {
|
|
return sharedObjects[path];
|
|
}
|
|
var so = new flash.net.SharedObject();
|
|
so._path = path;
|
|
var data = sessionStorage.getItem(path);
|
|
so._data = data ? JSON.parse(data) : {};
|
|
return so;
|
|
},
|
|
getRemote: function getRemote(name, remotePath, persistence, secure) {
|
|
notImplemented('SharedObject.getRemote');
|
|
},
|
|
defaultObjectEncoding: {
|
|
get: function defaultObjectEncoding() {
|
|
return _defaultObjectEncoding;
|
|
},
|
|
set: function defaultObjectEncoding(version) {
|
|
_defaultObjectEncoding = version;
|
|
}
|
|
}
|
|
},
|
|
instance: {
|
|
setDirty: function setDirty(propertyName) {
|
|
somewhatImplemented('SharedObject.setDirty');
|
|
},
|
|
invoke: function invoke(index) {
|
|
return invokeWithArgsArray.call(this, index, Array.prototype.slice.call(arguments, 1));
|
|
},
|
|
invokeWithArgsArray: function invokeWithArgsArray(index, args) {
|
|
return invokeWithArgsArray.call(this, index, args);
|
|
},
|
|
data: {
|
|
get: function data() {
|
|
return this._data;
|
|
}
|
|
},
|
|
objectEncoding: {
|
|
get: function objectEncoding() {
|
|
return this._objectEncoding;
|
|
},
|
|
set: function objectEncoding(version) {
|
|
this._objectEncoding = version;
|
|
}
|
|
},
|
|
client: {
|
|
get: function client() {
|
|
notImplemented('SharedObject.client');
|
|
return this._client;
|
|
},
|
|
set: function client(object) {
|
|
notImplemented('SharedObject.client');
|
|
this._client = object;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var SocketDefinition = function () {
|
|
return {
|
|
__class__: 'flash.net.Socket',
|
|
initialize: function () {
|
|
this._connected = false;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
internalGetSecurityErrorMessage: function internalGetSecurityErrorMessage(host, port) {
|
|
somewhatImplemented('Socket.internalGetSecurityErrorMessage');
|
|
return 'SecurityErrorEvent';
|
|
},
|
|
internalConnect: function internalConnect(host, port) {
|
|
somewhatImplemented('Socket.internalConnect');
|
|
throwError('SecurityError', Errors.SocketConnectError, host, port);
|
|
},
|
|
didFailureOccur: function didFailureOccur() {
|
|
somewhatImplemented('Socket.didFailureOccur');
|
|
return true;
|
|
},
|
|
readBytes: function readBytes(bytes, offset, length) {
|
|
notImplemented('Socket.readBytes');
|
|
},
|
|
writeBytes: function writeBytes(bytes, offset, length) {
|
|
notImplemented('Socket.writeBytes');
|
|
},
|
|
writeBoolean: function writeBoolean(value) {
|
|
notImplemented('Socket.writeBoolean');
|
|
},
|
|
writeByte: function writeByte(value) {
|
|
notImplemented('Socket.writeByte');
|
|
},
|
|
writeShort: function writeShort(value) {
|
|
notImplemented('Socket.writeShort');
|
|
},
|
|
writeInt: function writeInt(value) {
|
|
notImplemented('Socket.writeInt');
|
|
},
|
|
writeUnsignedInt: function writeUnsignedInt(value) {
|
|
notImplemented('Socket.writeUnsignedInt');
|
|
},
|
|
writeFloat: function writeFloat(value) {
|
|
notImplemented('Socket.writeFloat');
|
|
},
|
|
writeDouble: function writeDouble(value) {
|
|
notImplemented('Socket.writeDouble');
|
|
},
|
|
writeMultiByte: function writeMultiByte(value, charSet) {
|
|
notImplemented('Socket.writeMultiByte');
|
|
},
|
|
writeUTF: function writeUTF(value) {
|
|
notImplemented('Socket.writeUTF');
|
|
},
|
|
writeUTFBytes: function writeUTFBytes(value) {
|
|
notImplemented('Socket.writeUTFBytes');
|
|
},
|
|
readBoolean: function readBoolean() {
|
|
notImplemented('Socket.readBoolean');
|
|
},
|
|
readByte: function readByte() {
|
|
notImplemented('Socket.readByte');
|
|
},
|
|
readUnsignedByte: function readUnsignedByte() {
|
|
notImplemented('Socket.readUnsignedByte');
|
|
},
|
|
readShort: function readShort() {
|
|
notImplemented('Socket.readShort');
|
|
},
|
|
readUnsignedShort: function readUnsignedShort() {
|
|
notImplemented('Socket.readUnsignedShort');
|
|
},
|
|
readInt: function readInt() {
|
|
notImplemented('Socket.readInt');
|
|
},
|
|
readUnsignedInt: function readUnsignedInt() {
|
|
notImplemented('Socket.readUnsignedInt');
|
|
},
|
|
readFloat: function readFloat() {
|
|
notImplemented('Socket.readFloat');
|
|
},
|
|
readDouble: function readDouble() {
|
|
notImplemented('Socket.readDouble');
|
|
},
|
|
readMultiByte: function readMultiByte(length, charSet) {
|
|
notImplemented('Socket.readMultiByte');
|
|
},
|
|
readUTF: function readUTF() {
|
|
notImplemented('Socket.readUTF');
|
|
},
|
|
readUTFBytes: function readUTFBytes(length) {
|
|
notImplemented('Socket.readUTFBytes');
|
|
},
|
|
internalClose: function internalClose() {
|
|
notImplemented('Socket.internalClose');
|
|
},
|
|
flush: function flush() {
|
|
notImplemented('Socket.flush');
|
|
},
|
|
writeObject: function writeObject(object) {
|
|
notImplemented('Socket.writeObject');
|
|
},
|
|
readObject: function readObject() {
|
|
notImplemented('Socket.readObject');
|
|
},
|
|
bytesAvailable: {
|
|
get: function bytesAvailable() {
|
|
notImplemented('Socket.bytesAvailable');
|
|
return this._bytesAvailable;
|
|
}
|
|
},
|
|
connected: {
|
|
get: function connected() {
|
|
somewhatImplemented('Socket.connected');
|
|
return this._connected;
|
|
}
|
|
},
|
|
objectEncoding: {
|
|
get: function objectEncoding() {
|
|
notImplemented('Socket.objectEncoding');
|
|
return this._objectEncoding;
|
|
},
|
|
set: function objectEncoding(version) {
|
|
notImplemented('Socket.objectEncoding');
|
|
this._objectEncoding = version;
|
|
}
|
|
},
|
|
endian: {
|
|
get: function endian() {
|
|
notImplemented('Socket.endian');
|
|
return this._endian;
|
|
},
|
|
set: function endian(type) {
|
|
notImplemented('Socket.endian');
|
|
this._endian = type;
|
|
}
|
|
},
|
|
bytesPending: {
|
|
get: function bytesPending() {
|
|
notImplemented('Socket.bytesPending');
|
|
return this._bytesPending;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var URLLoaderDefinition = function () {
|
|
return {
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {}
|
|
},
|
|
script: {
|
|
static: {},
|
|
instance: {
|
|
data: 'public data',
|
|
dataFormat: 'public dataFormat',
|
|
bytesTotal: 'public bytesTotal',
|
|
bytesLoaded: 'public bytesLoaded',
|
|
load: 'public load'
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var URLRequestDefinition = function () {
|
|
function toFileLoadingServiceRequest() {
|
|
var obj = {};
|
|
obj.url = this._url;
|
|
obj.method = this._method;
|
|
obj.checkPolicyFile = this._checkPolicyFile;
|
|
if (this._data) {
|
|
obj.mimeType = this._contentType;
|
|
var ByteArrayClass = avm2.systemDomain.getClass('flash.utils.ByteArray');
|
|
if (ByteArrayClass.isInstanceOf(this._data)) {
|
|
obj.data = new Uint8Array(this._data.a, 0, this._data.length);
|
|
} else {
|
|
var data = this._data.asGetPublicProperty('toString').call(this._data);
|
|
if (this._method === 'GET') {
|
|
var i = obj.url.lastIndexOf('?');
|
|
obj.url = (i < 0 ? obj.url : obj.url.substring(0, i)) + '?' + data;
|
|
} else {
|
|
obj.data = data;
|
|
}
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
var def = {
|
|
initialize: function () {
|
|
this._url = null;
|
|
this._method = 'GET';
|
|
this._data = null;
|
|
this._digest = null;
|
|
this._contentType = 'application/x-www-form-urlencoded';
|
|
this._requestHeaders = null;
|
|
this._checkPolicyFile = true;
|
|
this._toFileRequest = toFileLoadingServiceRequest;
|
|
},
|
|
setMethod: function (val) {
|
|
this._method = val;
|
|
},
|
|
setRequestHeaders: function (val) {
|
|
this._requestHeaders = val;
|
|
},
|
|
get contentType() {
|
|
return this._contentType;
|
|
},
|
|
set contentType(val) {
|
|
this._contentType = val;
|
|
},
|
|
get data() {
|
|
return this._data;
|
|
},
|
|
set data(val) {
|
|
this._data = val;
|
|
},
|
|
get digest() {
|
|
return this._digest;
|
|
},
|
|
set digest(val) {
|
|
this._digest = val;
|
|
},
|
|
get method() {
|
|
return this._method;
|
|
},
|
|
set method(method) {
|
|
this._method = method;
|
|
},
|
|
get requestHeaders() {
|
|
return this._requestHeaders;
|
|
},
|
|
set requestHeaders(requestHeaders) {
|
|
this._requestHeaders = requestHeaders;
|
|
},
|
|
get url() {
|
|
return this._url;
|
|
},
|
|
set url(val) {
|
|
this._url = val;
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
setMethod: def.setMethod,
|
|
setRequestHeaders: def.setRequestHeaders,
|
|
contentType: desc(def, 'contentType'),
|
|
data: desc(def, 'data'),
|
|
digest: desc(def, 'digest'),
|
|
method: desc(def, 'method'),
|
|
requestHeaders: desc(def, 'requestHeaders'),
|
|
url: desc(def, 'url')
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var URLStreamDefinition = function () {
|
|
var def = {
|
|
initialize: function () {
|
|
this._stream = null;
|
|
this._connected = false;
|
|
this._littleEndian = false;
|
|
},
|
|
close: function close() {
|
|
this._session.close();
|
|
},
|
|
load: function load(request) {
|
|
var session = FileLoadingService.createSession();
|
|
var self = this;
|
|
var initStream = true;
|
|
session.onprogress = function (data, progressState) {
|
|
if (initStream) {
|
|
initStream = false;
|
|
var length = Math.max(progressState.bytesTotal, data.length);
|
|
var buffer = new ArrayBuffer(length);
|
|
self._stream = new Stream(buffer, 0, 0, length);
|
|
} else if (self._stream.end + data.length > self._stream.bytes.length) {
|
|
var length = self._stream.end + data.length;
|
|
var buffer = new ArrayBuffer(length);
|
|
var newStream = new Stream(buffer, 0, 0, length);
|
|
newStream.push(self._stream.bytes.subarray(0, self._stream.end));
|
|
self._stream = newStream;
|
|
}
|
|
self._stream.push(data);
|
|
var ProgressEventClass = avm2.systemDomain.getClass('flash.events.ProgressEvent');
|
|
self._dispatchEvent(ProgressEventClass.createInstance([
|
|
'progress',
|
|
false,
|
|
false,
|
|
progressState.bytesLoaded,
|
|
progressState.bytesTotal
|
|
]));
|
|
};
|
|
session.onerror = function (error) {
|
|
self._connected = false;
|
|
if (!self._stream) {
|
|
self._stream = new Stream(new ArrayBuffer(0), 0, 0, 0);
|
|
}
|
|
self._dispatchEvent(new flash.events.IOErrorEvent(flash.events.IOErrorEvent.class.IO_ERROR, false, false, error));
|
|
};
|
|
session.onopen = function () {
|
|
self._connected = true;
|
|
self._dispatchEvent(new flash.events.Event('open', false, false));
|
|
};
|
|
session.onhttpstatus = function (location, httpStatus, httpHeaders) {
|
|
var HTTPStatusEventClass = avm2.systemDomain.getClass('flash.events.HTTPStatusEvent');
|
|
var URLRequestHeaderClass = avm2.systemDomain.getClass('flash.net.URLRequestHeader');
|
|
var httpStatusEvent = HTTPStatusEventClass.createInstance([
|
|
'httpStatus',
|
|
false,
|
|
false,
|
|
httpStatus
|
|
]);
|
|
var headers = [];
|
|
httpHeaders.split(/(?:\n|\r?\n)/g).forEach(function (h) {
|
|
var m = /^([^:]+): (.*)$/.exec(h);
|
|
if (m) {
|
|
headers.push(URLRequestHeaderClass.createInstance([
|
|
m[1],
|
|
m[2]
|
|
]));
|
|
if (m[1] === 'Location') {
|
|
location = m[2];
|
|
}
|
|
}
|
|
});
|
|
httpStatusEvent.asSetPublicProperty('responseHeaders', headers);
|
|
httpStatusEvent.asSetPublicProperty('responseURL', location);
|
|
self._dispatchEvent(httpStatusEvent);
|
|
};
|
|
session.onclose = function () {
|
|
self._connected = false;
|
|
if (!self._stream) {
|
|
self._stream = new Stream(new ArrayBuffer(0), 0, 0, 0);
|
|
}
|
|
self._dispatchEvent(new flash.events.Event('complete', false, false));
|
|
};
|
|
session.open(request._toFileRequest());
|
|
this._session = session;
|
|
},
|
|
readBoolean: function readBoolean() {
|
|
notImplemented('URLStream.readBoolean');
|
|
},
|
|
readByte: function readByte() {
|
|
var stream = this._stream;
|
|
stream.ensure(1);
|
|
return stream.bytes[stream.pos++];
|
|
},
|
|
readBytes: function readBytes(bytes, offset, length) {
|
|
if (length < 0)
|
|
throw 'Invalid length argument';
|
|
var stream = this._stream;
|
|
if (!length)
|
|
length = stream.remaining();
|
|
else
|
|
stream.ensure(length);
|
|
bytes.writeRawBytes(stream.bytes.subarray(stream.pos, stream.pos + length), offset, length);
|
|
stream.pos += length;
|
|
},
|
|
readDouble: function readDouble() {
|
|
notImplemented('URLStream.readDouble');
|
|
},
|
|
readFloat: function readFloat() {
|
|
notImplemented('URLStream.readFloat');
|
|
},
|
|
readInt: function readInt() {
|
|
notImplemented('URLStream.readInt');
|
|
},
|
|
readMultiByte: function readMultiByte(length, charSet) {
|
|
notImplemented('URLStream.readMultiByte');
|
|
},
|
|
readObject: function readObject() {
|
|
notImplemented('URLStream.readObject');
|
|
},
|
|
readShort: function readShort() {
|
|
notImplemented('URLStream.readShort');
|
|
},
|
|
readUTF: function readUTF() {
|
|
return this.readUTFBytes(this.readUnsignedShort());
|
|
},
|
|
readUTFBytes: function readUTFBytes(length) {
|
|
if (length < 0)
|
|
throw 'Invalid length argument';
|
|
var stream = this._stream;
|
|
stream.ensure(length);
|
|
var str = utf8encode(stream.bytes.subarray(stream.pos, stream.pos + length));
|
|
stream.pos += length;
|
|
return str;
|
|
},
|
|
readUnsignedByte: function readUnsignedByte() {
|
|
notImplemented('URLStream.readUnsignedByte');
|
|
},
|
|
readUnsignedInt: function readUnsignedInt() {
|
|
notImplemented('URLStream.readUnsignedInt');
|
|
},
|
|
readUnsignedShort: function readUnsignedShort() {
|
|
var stream = this._stream;
|
|
stream.ensure(2);
|
|
var result = stream.getUint16(stream.pos, this._littleEndian);
|
|
stream.pos += 2;
|
|
return result;
|
|
},
|
|
get bytesAvailable() {
|
|
return this._stream.remaining();
|
|
},
|
|
get connected() {
|
|
return this._connected;
|
|
},
|
|
get endian() {
|
|
return this._littleEndian ? 'littleEndian' : 'bigEndian';
|
|
},
|
|
set endian(val) {
|
|
this._littleEndian = val == 'littleEndian';
|
|
},
|
|
get objectEncoding() {
|
|
notImplemented('URLStream.objectEncoding');
|
|
},
|
|
set objectEncoding(val) {
|
|
notImplemented('URLStream.objectEncoding');
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
close: def.close,
|
|
load: def.load,
|
|
readBoolean: def.readBoolean,
|
|
readByte: def.readByte,
|
|
readBytes: def.readBytes,
|
|
readDouble: def.readDouble,
|
|
readFloat: def.readFloat,
|
|
readInt: def.readInt,
|
|
readMultiByte: def.readMultiByte,
|
|
readObject: def.readObject,
|
|
readShort: def.readShort,
|
|
readUTF: def.readUTF,
|
|
readUTFBytes: def.readUTFBytes,
|
|
readUnsignedByte: def.readUnsignedByte,
|
|
readUnsignedInt: def.readUnsignedInt,
|
|
readUnsignedShort: def.readUnsignedShort,
|
|
bytesAvailable: desc(def, 'bytesAvailable'),
|
|
connected: desc(def, 'connected'),
|
|
endian: desc(def, 'endian'),
|
|
objectEncoding: desc(def, 'objectEncoding')
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
{
|
|
var ApplicationDomainDefinition = function () {
|
|
return {
|
|
__class__: 'flash.system.ApplicationDomain',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
currentDomain: {
|
|
get: function currentDomain() {
|
|
return new flash.system.ApplicationDomain(AVM2.currentDomain());
|
|
}
|
|
},
|
|
MIN_DOMAIN_MEMORY_LENGTH: {
|
|
get: function MIN_DOMAIN_MEMORY_LENGTH() {
|
|
notImplemented('ApplicationDomain.MIN_DOMAIN_MEMORY_LENGTH');
|
|
}
|
|
}
|
|
},
|
|
instance: {
|
|
ctor: function ctor(parentDomainOrNativeObject) {
|
|
if (parentDomainOrNativeObject instanceof ApplicationDomain) {
|
|
this.nativeObject = parentDomainOrNativeObject;
|
|
return;
|
|
}
|
|
var parentNativeObject = parentDomainOrNativeObject ? parentDomainOrNativeObject.nativeObject : AVM2.currentDomain().system;
|
|
this.nativeObject = new ApplicationDomain(parentNativeObject.vm, parentNativeObject);
|
|
},
|
|
getDefinition: function getDefinition(name) {
|
|
var simpleName = name.replace('::', '.');
|
|
return this.nativeObject.getProperty(Multiname.fromSimpleName(simpleName), true, true);
|
|
},
|
|
hasDefinition: function hasDefinition(name) {
|
|
if (name === undefined) {
|
|
return false;
|
|
}
|
|
var simpleName = name.replace('::', '.');
|
|
return !(!this.nativeObject.findDomainProperty(Multiname.fromSimpleName(simpleName), false, false));
|
|
},
|
|
getQualifiedDefinitionNames: function getQualifiedDefinitionNames() {
|
|
notImplemented('ApplicationDomain.getQualifiedDefinitionNames');
|
|
},
|
|
parentDomain: {
|
|
get: function parentDomain() {
|
|
var base = this.nativeObject.base;
|
|
if (!base) {
|
|
return undefined;
|
|
}
|
|
return new flash.system.ApplicationDomain(base);
|
|
}
|
|
},
|
|
domainMemory: {
|
|
get: function domainMemory() {
|
|
notImplemented('ApplicationDomain.domainMemory');
|
|
return this._domainMemory;
|
|
},
|
|
set: function domainMemory(mem) {
|
|
notImplemented('ApplicationDomain.domainMemory');
|
|
this._domainMemory = mem;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
static: Glue.ALL,
|
|
instance: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
}
|
|
var CapabilitiesDefinition = function () {
|
|
var def = {};
|
|
var os;
|
|
var userAgent = window.navigator.userAgent;
|
|
if (userAgent.indexOf('Macintosh') > 0) {
|
|
os = 'Mac OS 10.5.2';
|
|
} else if (userAgent.indexOf('Windows') > 0) {
|
|
os = 'Windows XP';
|
|
} else if (userAgent.indexOf('Linux') > 0) {
|
|
os = 'Linux';
|
|
} else if (/(iPad|iPhone|iPod|Android)/.test(userAgent)) {
|
|
os = 'iPhone3,1';
|
|
} else {
|
|
notImplemented();
|
|
}
|
|
def.__glue__ = {
|
|
native: {
|
|
static: {
|
|
version: {
|
|
get: function version() {
|
|
return 'SHUMWAY 10,0,0,0';
|
|
},
|
|
enumerable: true
|
|
},
|
|
os: {
|
|
get: function () {
|
|
return os;
|
|
},
|
|
enumerable: true
|
|
},
|
|
serverString: {
|
|
get: function () {
|
|
var str = toKeyValueArray({
|
|
OS: os
|
|
}).map(function (pair) {
|
|
return pair[0] + '=' + encodeURIComponent(pair[1]);
|
|
}).join('&');
|
|
somewhatImplemented('Capabilities.serverString: ' + str);
|
|
return str;
|
|
}
|
|
},
|
|
hasAccessibility: {
|
|
get: function hasAccessibility() {
|
|
somewhatImplemented('Capabilities.hasAccessibility');
|
|
return false;
|
|
}
|
|
},
|
|
isDebugger: {
|
|
get: function isDebugger() {
|
|
return false;
|
|
}
|
|
},
|
|
screenResolutionX: {
|
|
get: function screenResolutionX() {
|
|
return window.screen.width;
|
|
}
|
|
},
|
|
screenResolutionY: {
|
|
get: function screenResolutionY() {
|
|
return window.screen.height;
|
|
}
|
|
},
|
|
manufacturer: {
|
|
get: function manufacturer() {
|
|
somewhatImplemented('Capabilities.manufacturer');
|
|
return 'Mozilla Research';
|
|
}
|
|
},
|
|
language: {
|
|
get: function language() {
|
|
somewhatImplemented('Capabilities.language');
|
|
return 'en';
|
|
}
|
|
},
|
|
playerType: {
|
|
get: function playerType() {
|
|
somewhatImplemented('Capabilities.playerType');
|
|
return 'PlugIn';
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
static: scriptProperties('public', [
|
|
'version',
|
|
'os'
|
|
])
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var FSCommandDefinition = function () {
|
|
var def = {};
|
|
function fscommand(command, parameters) {
|
|
console.log('FSCommand: ' + command + '; ' + parameters);
|
|
switch (command.toLowerCase()) {
|
|
case 'quit':
|
|
renderingTerminated = true;
|
|
return;
|
|
case 'debugger':
|
|
debugger;
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
def.__glue__ = {
|
|
native: {
|
|
static: {
|
|
_fscommand: fscommand
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var SecurityDefinition = function () {
|
|
var _exactSettings;
|
|
return {
|
|
__class__: 'flash.system.Security',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
allowDomain: function allowDomain() {
|
|
somewhatImplemented('Security.allowDomain ["' + Array.prototype.join.call(arguments, '", "') + '"]');
|
|
},
|
|
allowInsecureDomain: function allowInsecureDomain() {
|
|
somewhatImplemented('Security.allowInsecureDomain');
|
|
},
|
|
loadPolicyFile: function loadPolicyFile(url) {
|
|
somewhatImplemented('Security.loadPolicyFile');
|
|
},
|
|
duplicateSandboxBridgeInputArguments: function duplicateSandboxBridgeInputArguments(toplevel, args) {
|
|
notImplemented('Security.duplicateSandboxBridgeInputArguments');
|
|
},
|
|
duplicateSandboxBridgeOutputArgument: function duplicateSandboxBridgeOutputArgument(toplevel, arg) {
|
|
notImplemented('Security.duplicateSandboxBridgeOutputArgument');
|
|
},
|
|
showSettings: function showSettings(panel) {
|
|
notImplemented('Security.showSettings');
|
|
},
|
|
exactSettings: {
|
|
get: function () {
|
|
return _exactSettings;
|
|
},
|
|
set: function (value) {
|
|
_exactSettings = value;
|
|
}
|
|
},
|
|
disableAVM1Loading: {
|
|
get: function disableAVM1Loading() {
|
|
notImplemented('Security.disableAVM1Loading');
|
|
},
|
|
set: function disableAVM1Loading(value) {
|
|
notImplemented('Security.disableAVM1Loading');
|
|
}
|
|
},
|
|
sandboxType: {
|
|
get: function () {
|
|
somewhatImplemented('Security.sandboxType');
|
|
return 'remote';
|
|
}
|
|
},
|
|
pageDomain: {
|
|
get: function pageDomain() {
|
|
somewhatImplemented('Security.pageDomain');
|
|
var pageHost = FileLoadingService.resolveUrl('/');
|
|
var parts = pageHost.split('/');
|
|
parts.pop();
|
|
return parts.pop();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var SecurityDomainDefinition = function () {
|
|
return {
|
|
__class__: 'flash.system.SecurityDomain',
|
|
initialize: function () {
|
|
},
|
|
_currentDomain: null,
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
currentDomain: {
|
|
get: function () {
|
|
return this._currentDomain;
|
|
}
|
|
}
|
|
},
|
|
instance: {
|
|
ctor_impl: function ctor_impl() {
|
|
notImplemented('SecurityDomain.ctor_impl');
|
|
},
|
|
domainID: {
|
|
get: function domainID() {
|
|
notImplemented('SecurityDomain.domainID');
|
|
return this._domainID;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var SystemDefinition = function () {
|
|
return {
|
|
__class__: 'flash.system.System',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
setClipboard: function setClipboard(string) {
|
|
FirefoxCom.request('setClipboard', string);
|
|
TelemetryService.reportTelemetry({
|
|
topic: 'feature',
|
|
feature: CLIPBOARD_FEATURE
|
|
});
|
|
},
|
|
pause: function pause() {
|
|
somewhatImplemented('System.pause');
|
|
},
|
|
resume: function resume() {
|
|
somewhatImplemented('System.resume');
|
|
},
|
|
exit: function exit(code) {
|
|
somewhatImplemented('System.exit');
|
|
renderingTerminated = true;
|
|
},
|
|
gc: function gc() {
|
|
somewhatImplemented('System.gc');
|
|
},
|
|
pauseForGCIfCollectionImminent: function pauseForGCIfCollectionImminent(imminence) {
|
|
notImplemented('System.pauseForGCIfCollectionImminent');
|
|
},
|
|
disposeXML: function disposeXML(node) {
|
|
notImplemented('System.disposeXML');
|
|
},
|
|
ime: {
|
|
get: function ime() {
|
|
notImplemented('System.ime');
|
|
}
|
|
},
|
|
totalMemoryNumber: {
|
|
get: function totalMemoryNumber() {
|
|
if (performance.memory) {
|
|
return performance.memory.usedJSHeapSize;
|
|
}
|
|
return 0;
|
|
}
|
|
},
|
|
freeMemory: {
|
|
get: function freeMemory() {
|
|
notImplemented('System.freeMemory');
|
|
}
|
|
},
|
|
privateMemory: {
|
|
get: function privateMemory() {
|
|
return 0;
|
|
}
|
|
},
|
|
processCPUUsage: {
|
|
get: function processCPUUsage() {
|
|
notImplemented('System.processCPUUsage');
|
|
}
|
|
},
|
|
useCodePage: {
|
|
get: function useCodePage() {
|
|
somewhatImplemented('System.useCodePage');
|
|
return false;
|
|
},
|
|
set: function useCodePage(value) {
|
|
notImplemented('System.useCodePage');
|
|
}
|
|
},
|
|
vmVersion: {
|
|
get: function vmVersion() {
|
|
somewhatImplemented('System.vmVersion');
|
|
return '1.0 shumway';
|
|
}
|
|
},
|
|
swfVersion: {
|
|
get: function () {
|
|
return 19;
|
|
}
|
|
},
|
|
apiVersion: {
|
|
get: function () {
|
|
return 26;
|
|
}
|
|
},
|
|
getArgv: function () {
|
|
return [];
|
|
},
|
|
getRunmode: function () {
|
|
return 'mixed';
|
|
}
|
|
},
|
|
instance: {}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
{
|
|
var FontDefinition = function () {
|
|
var fonts = [];
|
|
var fontsByUniqueName = Object.create(null);
|
|
var fontsByNameStyleType = Object.create(null);
|
|
var _deviceFontMetrics;
|
|
var def = {
|
|
__class__: 'flash.text.Font',
|
|
initialize: function () {
|
|
var s = this.symbol;
|
|
if (s) {
|
|
this._fontName = s.name || null;
|
|
this._uniqueName = s.uniqueName;
|
|
if (s.bold) {
|
|
if (s.italic) {
|
|
this._fontStyle = 'boldItalic';
|
|
} else {
|
|
this._fontStyle = 'bold';
|
|
}
|
|
} else if (s.italic) {
|
|
this._fontStyle = 'italic';
|
|
} else {
|
|
this._fontStyle = 'regular';
|
|
}
|
|
var metrics = s.metrics;
|
|
metrics.height = metrics.ascent + metrics.descent + metrics.leading;
|
|
this._metrics = metrics;
|
|
this._fontType = 'embedded';
|
|
fonts.push(this);
|
|
fontsByUniqueName[this._uniqueName] = this;
|
|
var ident = this._fontName.toLowerCase() + '_' + this._fontStyle + '_embedded';
|
|
fontsByNameStyleType[ident] = this;
|
|
}
|
|
},
|
|
get fontName() {
|
|
return this._fontName;
|
|
},
|
|
get fontStyle() {
|
|
return this._fontStyle;
|
|
},
|
|
get fontType() {
|
|
return this._fontType;
|
|
},
|
|
hasGlyphs: function hasGlyphs(str) {
|
|
return true;
|
|
},
|
|
getFont: function (name, style, embedded) {
|
|
var ident = name.toLowerCase() + '_' + style + (embedded ? '_embedded' : '_device');
|
|
var font = fontsByNameStyleType[ident];
|
|
if (font) {
|
|
return font;
|
|
}
|
|
font = new flash.text.Font();
|
|
font._fontName = font._uniqueName = name;
|
|
font._fontStyle = style;
|
|
font._fontType = 'device';
|
|
var metrics = deviceFontMetrics()[name];
|
|
if (!metrics) {
|
|
metrics = deviceFontMetrics().serif;
|
|
font._fontName = font._uniqueName = 'serif';
|
|
}
|
|
font._metrics = {
|
|
ascent: metrics[0],
|
|
descent: metrics[1],
|
|
leading: metrics[2]
|
|
};
|
|
font._metrics.height = metrics[0] + metrics[1] + metrics[2];
|
|
fontsByNameStyleType[ident] = font;
|
|
return font;
|
|
},
|
|
getFontByUniqueName: function (name) {
|
|
return fontsByUniqueName[name];
|
|
}
|
|
};
|
|
function enumerateFonts(device) {
|
|
return fonts.slice();
|
|
}
|
|
function registerFont(font) {
|
|
somewhatImplemented('Font.registerFont');
|
|
}
|
|
function deviceFontMetrics() {
|
|
if (_deviceFontMetrics) {
|
|
return _deviceFontMetrics;
|
|
}
|
|
var userAgent = window.navigator.userAgent;
|
|
if (userAgent.indexOf('Windows') > -1) {
|
|
_deviceFontMetrics = DEVICE_FONT_METRICS_WIN;
|
|
} else if (/(Macintosh|iPad|iPhone|iPod|Android)/.test(userAgent)) {
|
|
_deviceFontMetrics = DEVICE_FONT_METRICS_MAC;
|
|
} else {
|
|
_deviceFontMetrics = DEVICE_FONT_METRICS_LINUX;
|
|
}
|
|
return _deviceFontMetrics;
|
|
}
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
fontName: desc(def, 'fontName'),
|
|
fontStyle: desc(def, 'fontStyle'),
|
|
fontType: desc(def, 'fontType'),
|
|
hasGlyphs: def.hasGlyphs
|
|
},
|
|
static: {
|
|
enumerateFonts: enumerateFonts,
|
|
registerFont: registerFont
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var DEVICE_FONT_METRICS_WIN = {
|
|
'serif': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'sans-serif': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'monospace': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'birch std': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'blackoak std': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'chaparral pro': [
|
|
0.8333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'chaparral pro light': [
|
|
0.8333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'charlemagne std': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'cooper std black': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'giddyup std': [
|
|
0.8333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'hobo std': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka gothic pro b': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'kozuka gothic pro el': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'kozuka gothic pro h': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'kozuka gothic pro l': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka gothic pro m': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka gothic pro r': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka mincho pro b': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'kozuka mincho pro el': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'kozuka mincho pro h': [
|
|
1.1667,
|
|
0.25,
|
|
0
|
|
],
|
|
'kozuka mincho pro l': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'kozuka mincho pro m': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'kozuka mincho pro r': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'mesquite std': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'minion pro cond': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'minion pro med': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'minion pro smbd': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'myriad arabic': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'nueva std': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'nueva std cond': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'ocr a std': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'orator std': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'poplar std': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'prestige elite std': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'rosewood std regular': [
|
|
0.8333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'stencil std': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'trajan pro': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'kozuka gothic pr6n b': [
|
|
1.4167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'kozuka gothic pr6n el': [
|
|
1.4167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka gothic pr6n h': [
|
|
1.4167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'kozuka gothic pr6n l': [
|
|
1.4167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka gothic pr6n m': [
|
|
1.5,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka gothic pr6n r': [
|
|
1.4167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka mincho pr6n b': [
|
|
1.3333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka mincho pr6n el': [
|
|
1.3333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka mincho pr6n h': [
|
|
1.4167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka mincho pr6n l': [
|
|
1.3333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka mincho pr6n m': [
|
|
1.3333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kozuka mincho pr6n r': [
|
|
1.3333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'letter gothic std': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'minion pro': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'myriad hebrew': [
|
|
0.8333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'myriad pro': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'myriad pro cond': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'myriad pro light': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'marlett': [
|
|
1,
|
|
0,
|
|
0
|
|
],
|
|
'arial': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'arabic transparent': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial baltic': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial ce': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial cyr': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial greek': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial tur': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'batang': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'batangche': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'gungsuh': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'gungsuhche': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'courier new': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'courier new baltic': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'courier new ce': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'courier new cyr': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'courier new greek': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'courier new tur': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'daunpenh': [
|
|
0.6667,
|
|
0.6667,
|
|
0
|
|
],
|
|
'dokchampa': [
|
|
1.4167,
|
|
0.5833,
|
|
0
|
|
],
|
|
'estrangelo edessa': [
|
|
0.75,
|
|
0.3333,
|
|
0
|
|
],
|
|
'euphemia': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'gautami': [
|
|
1.1667,
|
|
0.8333,
|
|
0
|
|
],
|
|
'vani': [
|
|
1.0833,
|
|
0.75,
|
|
0
|
|
],
|
|
'gulim': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'gulimche': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'dotum': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'dotumche': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'impact': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'iskoola pota': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kalinga': [
|
|
1.0833,
|
|
0.5,
|
|
0
|
|
],
|
|
'kartika': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'khmer ui': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'lao ui': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'latha': [
|
|
1.0833,
|
|
0.4167,
|
|
0
|
|
],
|
|
'lucida console': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'malgun gothic': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'mangal': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'meiryo': [
|
|
1.0833,
|
|
0.4167,
|
|
0
|
|
],
|
|
'meiryo ui': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'microsoft himalaya': [
|
|
0.5833,
|
|
0.4167,
|
|
0
|
|
],
|
|
'microsoft jhenghei': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'microsoft yahei': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'mingliu': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'pmingliu': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'mingliu_hkscs': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'mingliu-extb': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'pmingliu-extb': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'mingliu_hkscs-extb': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'mongolian baiti': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'ms gothic': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'ms pgothic': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'ms ui gothic': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'ms mincho': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'ms pmincho': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'mv boli': [
|
|
1.1667,
|
|
0.25,
|
|
0
|
|
],
|
|
'microsoft new tai lue': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'nyala': [
|
|
0.9167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'microsoft phagspa': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'plantagenet cherokee': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'raavi': [
|
|
1.0833,
|
|
0.6667,
|
|
0
|
|
],
|
|
'segoe script': [
|
|
1.0833,
|
|
0.5,
|
|
0
|
|
],
|
|
'segoe ui': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'segoe ui semibold': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'segoe ui light': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'segoe ui symbol': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'shruti': [
|
|
1.0833,
|
|
0.5,
|
|
0
|
|
],
|
|
'simsun': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'nsimsun': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'simsun-extb': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'sylfaen': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'microsoft tai le': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'times new roman': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'times new roman baltic': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'times new roman ce': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'times new roman cyr': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'times new roman greek': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'times new roman tur': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'tunga': [
|
|
1.0833,
|
|
0.75,
|
|
0
|
|
],
|
|
'vrinda': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'shonar bangla': [
|
|
0.8333,
|
|
0.5,
|
|
0
|
|
],
|
|
'microsoft yi baiti': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'tahoma': [
|
|
1,
|
|
0.1667,
|
|
0
|
|
],
|
|
'microsoft sans serif': [
|
|
1.0833,
|
|
0.1667,
|
|
0
|
|
],
|
|
'angsana new': [
|
|
0.9167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'aparajita': [
|
|
0.75,
|
|
0.4167,
|
|
0
|
|
],
|
|
'cordia new': [
|
|
0.9167,
|
|
0.5,
|
|
0
|
|
],
|
|
'ebrima': [
|
|
1.0833,
|
|
0.5,
|
|
0
|
|
],
|
|
'gisha': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'kokila': [
|
|
0.8333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'leelawadee': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'microsoft uighur': [
|
|
1.0833,
|
|
0.5,
|
|
0
|
|
],
|
|
'moolboran': [
|
|
0.6667,
|
|
0.6667,
|
|
0
|
|
],
|
|
'symbol': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'utsaah': [
|
|
0.8333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'vijaya': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'wingdings': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'andalus': [
|
|
1.3333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'arabic typesetting': [
|
|
0.8333,
|
|
0.5,
|
|
0
|
|
],
|
|
'simplified arabic': [
|
|
1.3333,
|
|
0.5,
|
|
0
|
|
],
|
|
'simplified arabic fixed': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'sakkal majalla': [
|
|
0.9167,
|
|
0.5,
|
|
0
|
|
],
|
|
'traditional arabic': [
|
|
1.3333,
|
|
0.5,
|
|
0
|
|
],
|
|
'aharoni': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'david': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'frankruehl': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'fangsong': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'simhei': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'kaiti': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'browallia new': [
|
|
0.8333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'lucida sans unicode': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial black': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'calibri': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'cambria': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'cambria math': [
|
|
3.0833,
|
|
2.5,
|
|
0
|
|
],
|
|
'candara': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'comic sans ms': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'consolas': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'constantia': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'corbel': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'franklin gothic medium': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'gabriola': [
|
|
1.1667,
|
|
0.6667,
|
|
0
|
|
],
|
|
'georgia': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'palatino linotype': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'segoe print': [
|
|
1.25,
|
|
0.5,
|
|
0
|
|
],
|
|
'trebuchet ms': [
|
|
1.0833,
|
|
0.4167,
|
|
0
|
|
],
|
|
'verdana': [
|
|
1,
|
|
0.1667,
|
|
0
|
|
],
|
|
'webdings': [
|
|
1.0833,
|
|
0.5,
|
|
0
|
|
],
|
|
'lucida bright': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'lucida sans': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'lucida sans typewriter': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'gentium basic': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'dejavu serif condensed': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'arimo': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'dejavu sans condensed': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'dejavu sans': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'dejavu sans light': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'opensymbol': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'gentium book basic': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'dejavu sans mono': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'dejavu serif': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'calibri light': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
]
|
|
};
|
|
var DEVICE_FONT_METRICS_MAC = {
|
|
'al bayan plain': [
|
|
1,
|
|
0.5,
|
|
0
|
|
],
|
|
'al bayan bold': [
|
|
1,
|
|
0.5833,
|
|
0
|
|
],
|
|
'american typewriter': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'american typewriter bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'american typewriter condensed': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'american typewriter condensed bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'american typewriter condensed light': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'american typewriter light': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'andale mono': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'apple symbols': [
|
|
0.6667,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial bold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial hebrew': [
|
|
0.75,
|
|
0.3333,
|
|
0
|
|
],
|
|
'arial hebrew bold': [
|
|
0.75,
|
|
0.3333,
|
|
0
|
|
],
|
|
'arial': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial narrow': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial narrow bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial narrow bold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial narrow italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial rounded mt bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'arial unicode ms': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'avenir black': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir black oblique': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir book': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir book oblique': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir heavy': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir heavy oblique': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir light': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir light oblique': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir medium': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir medium oblique': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir oblique': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir roman': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next bold': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next bold italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next demi bold': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next demi bold italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next heavy': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next heavy italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next medium': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next medium italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next regular': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next ultra light': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next ultra light italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed bold': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed bold italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed demi bold': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed demi bold italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed heavy': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed heavy italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed medium': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed medium italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed regular': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed ultra light': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'avenir next condensed ultra light italic': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'ayuthaya': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'baghdad': [
|
|
0.9167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'bangla mn': [
|
|
0.9167,
|
|
0.6667,
|
|
0
|
|
],
|
|
'bangla mn bold': [
|
|
0.9167,
|
|
0.6667,
|
|
0
|
|
],
|
|
'bangla sangam mn': [
|
|
0.9167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'bangla sangam mn bold': [
|
|
0.9167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'baskerville': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'baskerville bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'baskerville bold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'baskerville italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'baskerville semibold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'baskerville semibold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'big caslon medium': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'brush script mt italic': [
|
|
0.9167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'chalkboard': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'chalkboard bold': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'chalkboard se bold': [
|
|
1.1667,
|
|
0.25,
|
|
0
|
|
],
|
|
'chalkboard se light': [
|
|
1.1667,
|
|
0.25,
|
|
0
|
|
],
|
|
'chalkboard se regular': [
|
|
1.1667,
|
|
0.25,
|
|
0
|
|
],
|
|
'chalkduster': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'charcoal cy': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'cochin': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'cochin bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'cochin bold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'cochin italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'comic sans ms': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'comic sans ms bold': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'copperplate': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'copperplate bold': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'copperplate light': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'corsiva hebrew': [
|
|
0.6667,
|
|
0.3333,
|
|
0
|
|
],
|
|
'corsiva hebrew bold': [
|
|
0.6667,
|
|
0.3333,
|
|
0
|
|
],
|
|
'courier': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'courier bold': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'courier bold oblique': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'courier oblique': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'courier new bold italic': [
|
|
0.8333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'courier new bold': [
|
|
0.8333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'courier new italic': [
|
|
0.8333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'courier new': [
|
|
0.8333,
|
|
0.3333,
|
|
0
|
|
],
|
|
'biaukai': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'damascus': [
|
|
0.5833,
|
|
0.4167,
|
|
0
|
|
],
|
|
'damascus bold': [
|
|
0.5833,
|
|
0.4167,
|
|
0
|
|
],
|
|
'decotype naskh': [
|
|
1.1667,
|
|
0.6667,
|
|
0
|
|
],
|
|
'devanagari mt': [
|
|
0.9167,
|
|
0.6667,
|
|
0
|
|
],
|
|
'devanagari mt bold': [
|
|
0.9167,
|
|
0.6667,
|
|
0
|
|
],
|
|
'devanagari sangam mn': [
|
|
0.9167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'devanagari sangam mn bold': [
|
|
0.9167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'didot': [
|
|
0.9167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'didot bold': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'didot italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'euphemia ucas': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'euphemia ucas bold': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'euphemia ucas italic': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'futura condensed extrabold': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'futura condensed medium': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'futura medium': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'futura medium italic': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'gb18030 bitmap': [
|
|
1,
|
|
0.6667,
|
|
0
|
|
],
|
|
'geeza pro': [
|
|
0.9167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'geeza pro bold': [
|
|
0.9167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'geneva': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'geneva cy': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'georgia': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'georgia bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'georgia bold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'georgia italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'gill sans': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'gill sans bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'gill sans bold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'gill sans italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'gill sans light': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'gill sans light italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'gujarati mt': [
|
|
0.9167,
|
|
0.6667,
|
|
0
|
|
],
|
|
'gujarati mt bold': [
|
|
0.9167,
|
|
0.6667,
|
|
0
|
|
],
|
|
'gujarati sangam mn': [
|
|
0.8333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'gujarati sangam mn bold': [
|
|
0.8333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'gurmukhi mn': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'gurmukhi mn bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'gurmukhi sangam mn': [
|
|
0.9167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'gurmukhi sangam mn bold': [
|
|
0.9167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'helvetica': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica bold': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica bold oblique': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica light': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica light oblique': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica oblique': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue bold': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue bold italic': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue condensed black': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue condensed bold': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue light': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue light italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue medium': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue ultralight': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'helvetica neue ultralight italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'herculanum': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'hiragino kaku gothic pro w3': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino kaku gothic pro w6': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino kaku gothic pron w3': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino kaku gothic pron w6': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino kaku gothic std w8': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino kaku gothic stdn w8': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino maru gothic pro w4': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino maru gothic pron w4': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino mincho pro w3': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino mincho pro w6': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino mincho pron w3': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino mincho pron w6': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino sans gb w3': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hiragino sans gb w6': [
|
|
0.9167,
|
|
0.0833,
|
|
0
|
|
],
|
|
'hoefler text black': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'hoefler text black italic': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'hoefler text italic': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'hoefler text ornaments': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'hoefler text': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'impact': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'inaimathi': [
|
|
0.8333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'headlinea regular': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'pilgi regular': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'gungseo regular': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'pcmyungjo regular': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'kailasa regular': [
|
|
1.0833,
|
|
0.5833,
|
|
0
|
|
],
|
|
'kannada mn': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'kannada mn bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'kannada sangam mn': [
|
|
1,
|
|
0.5833,
|
|
0
|
|
],
|
|
'kannada sangam mn bold': [
|
|
1,
|
|
0.5833,
|
|
0
|
|
],
|
|
'kefa bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'kefa regular': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'khmer mn': [
|
|
1,
|
|
0.6667,
|
|
0
|
|
],
|
|
'khmer mn bold': [
|
|
1,
|
|
0.6667,
|
|
0
|
|
],
|
|
'khmer sangam mn': [
|
|
1.0833,
|
|
0.6667,
|
|
0
|
|
],
|
|
'kokonor regular': [
|
|
1.0833,
|
|
0.5833,
|
|
0
|
|
],
|
|
'krungthep': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'kufistandardgk': [
|
|
0.9167,
|
|
0.5,
|
|
0
|
|
],
|
|
'lao mn': [
|
|
0.9167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'lao mn bold': [
|
|
0.9167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'lao sangam mn': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'apple ligothic medium': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'lihei pro': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'lisong pro': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'lucida grande': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'lucida grande bold': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'malayalam mn': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'malayalam mn bold': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'malayalam sangam mn': [
|
|
0.8333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'malayalam sangam mn bold': [
|
|
0.8333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'marion bold': [
|
|
0.6667,
|
|
0.3333,
|
|
0
|
|
],
|
|
'marion italic': [
|
|
0.6667,
|
|
0.3333,
|
|
0
|
|
],
|
|
'marion regular': [
|
|
0.6667,
|
|
0.3333,
|
|
0
|
|
],
|
|
'marker felt thin': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'marker felt wide': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'menlo bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'menlo bold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'menlo italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'menlo regular': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'microsoft sans serif': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'monaco': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'gurmukhi mt': [
|
|
0.8333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'mshtakan': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'mshtakan bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'mshtakan boldoblique': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'mshtakan oblique': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'myanmar mn': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'myanmar mn bold': [
|
|
1,
|
|
0.4167,
|
|
0
|
|
],
|
|
'myanmar sangam mn': [
|
|
0.9167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'nadeem': [
|
|
0.9167,
|
|
0.4167,
|
|
0
|
|
],
|
|
'nanum brush script': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'nanumgothic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'nanumgothic bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'nanumgothic extrabold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'nanummyeongjo': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'nanummyeongjo bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'nanummyeongjo extrabold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'nanum pen script': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'optima bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'optima bold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'optima extrablack': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'optima italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'optima regular': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'oriya mn': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'oriya mn bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'oriya sangam mn': [
|
|
0.8333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'oriya sangam mn bold': [
|
|
0.8333,
|
|
0.4167,
|
|
0
|
|
],
|
|
'osaka': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'osaka-mono': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'palatino bold': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'palatino bold italic': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'palatino italic': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'palatino': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'papyrus': [
|
|
0.9167,
|
|
0.5833,
|
|
0
|
|
],
|
|
'papyrus condensed': [
|
|
0.9167,
|
|
0.5833,
|
|
0
|
|
],
|
|
'plantagenet cherokee': [
|
|
0.6667,
|
|
0.25,
|
|
0
|
|
],
|
|
'raanana': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'raanana bold': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'hei regular': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'kai regular': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'stfangsong': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'stheiti': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'heiti sc light': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'heiti sc medium': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'heiti tc light': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'heiti tc medium': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'stkaiti': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'kaiti sc black': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kaiti sc bold': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'kaiti sc regular': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'stsong': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'songti sc black': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'songti sc bold': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'songti sc light': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'songti sc regular': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'stxihei': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'sathu': [
|
|
0.9167,
|
|
0.3333,
|
|
0
|
|
],
|
|
'silom': [
|
|
1,
|
|
0.3333,
|
|
0
|
|
],
|
|
'sinhala mn': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'sinhala mn bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'sinhala sangam mn': [
|
|
1.1667,
|
|
0.3333,
|
|
0
|
|
],
|
|
'sinhala sangam mn bold': [
|
|
1.1667,
|
|
0.3333,
|
|
0
|
|
],
|
|
'skia regular': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'symbol': [
|
|
0.6667,
|
|
0.3333,
|
|
0
|
|
],
|
|
'tahoma negreta': [
|
|
1,
|
|
0.1667,
|
|
0
|
|
],
|
|
'tamil mn': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'tamil mn bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'tamil sangam mn': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'tamil sangam mn bold': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'telugu mn': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'telugu mn bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'telugu sangam mn': [
|
|
1,
|
|
0.5833,
|
|
0
|
|
],
|
|
'telugu sangam mn bold': [
|
|
1,
|
|
0.5833,
|
|
0
|
|
],
|
|
'thonburi': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'thonburi bold': [
|
|
1.0833,
|
|
0.25,
|
|
0
|
|
],
|
|
'times bold': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'times bold italic': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'times italic': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'times roman': [
|
|
0.75,
|
|
0.25,
|
|
0
|
|
],
|
|
'times new roman bold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'times new roman bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'times new roman italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'times new roman': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'trebuchet ms bold italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'trebuchet ms': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'trebuchet ms bold': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'trebuchet ms italic': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'verdana': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'verdana bold': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'verdana bold italic': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'verdana italic': [
|
|
1,
|
|
0.25,
|
|
0
|
|
],
|
|
'webdings': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'wingdings 2': [
|
|
0.8333,
|
|
0.25,
|
|
0
|
|
],
|
|
'wingdings 3': [
|
|
0.9167,
|
|
0.25,
|
|
0
|
|
],
|
|
'yuppy sc regular': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'yuppy tc regular': [
|
|
1.0833,
|
|
0.3333,
|
|
0
|
|
],
|
|
'zapf dingbats': [
|
|
0.8333,
|
|
0.1667,
|
|
0
|
|
],
|
|
'zapfino': [
|
|
1.9167,
|
|
1.5,
|
|
0
|
|
]
|
|
};
|
|
var DEVICE_FONT_METRICS_LINUX = {
|
|
'kacstfarsi': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'meera': [
|
|
0.682,
|
|
0.4413,
|
|
0
|
|
],
|
|
'freemono': [
|
|
0.8023,
|
|
0.2006,
|
|
0
|
|
],
|
|
'undotum': [
|
|
1.0029,
|
|
0.2808,
|
|
0
|
|
],
|
|
'loma': [
|
|
1.1634,
|
|
0.4814,
|
|
0
|
|
],
|
|
'century schoolbook l': [
|
|
1.0029,
|
|
0.3209,
|
|
0
|
|
],
|
|
'kacsttitlel': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'undinaru': [
|
|
1.0029,
|
|
0.2407,
|
|
0
|
|
],
|
|
'ungungseo': [
|
|
1.0029,
|
|
0.2808,
|
|
0
|
|
],
|
|
'garuda': [
|
|
1.3238,
|
|
0.6017,
|
|
0
|
|
],
|
|
'rekha': [
|
|
1.1232,
|
|
0.2808,
|
|
0
|
|
],
|
|
'purisa': [
|
|
1.1232,
|
|
0.5215,
|
|
0
|
|
],
|
|
'dejavu sans mono': [
|
|
0.9628,
|
|
0.2407,
|
|
0
|
|
],
|
|
'vemana2000': [
|
|
0.8825,
|
|
0.8424,
|
|
0
|
|
],
|
|
'kacstoffice': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'umpush': [
|
|
1.2837,
|
|
0.682,
|
|
0
|
|
],
|
|
'opensymbol': [
|
|
0.8023,
|
|
0.2006,
|
|
0
|
|
],
|
|
'sawasdee': [
|
|
1.1232,
|
|
0.4413,
|
|
0
|
|
],
|
|
'urw palladio l': [
|
|
1.0029,
|
|
0.3209,
|
|
0
|
|
],
|
|
'freeserif': [
|
|
0.9227,
|
|
0.3209,
|
|
0
|
|
],
|
|
'kacstdigital': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'ubuntu condensed': [
|
|
0.9628,
|
|
0.2006,
|
|
0
|
|
],
|
|
'unpilgi': [
|
|
1.0029,
|
|
0.4413,
|
|
0
|
|
],
|
|
'mry_kacstqurn': [
|
|
1.4442,
|
|
0.7221,
|
|
0
|
|
],
|
|
'urw gothic l': [
|
|
1.0029,
|
|
0.2407,
|
|
0
|
|
],
|
|
'dingbats': [
|
|
0.8424,
|
|
0.1605,
|
|
0
|
|
],
|
|
'urw chancery l': [
|
|
1.0029,
|
|
0.3209,
|
|
0
|
|
],
|
|
'phetsarath ot': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'tlwg typist': [
|
|
0.8825,
|
|
0.4012,
|
|
0
|
|
],
|
|
'kacstletter': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'utkal': [
|
|
1.2035,
|
|
0.6418,
|
|
0
|
|
],
|
|
'dejavu sans light': [
|
|
0.9628,
|
|
0.2407,
|
|
0
|
|
],
|
|
'norasi': [
|
|
1.2436,
|
|
0.5215,
|
|
0
|
|
],
|
|
'dejavu serif condensed': [
|
|
0.9628,
|
|
0.2407,
|
|
0
|
|
],
|
|
'kacstone': [
|
|
1.2436,
|
|
0.6418,
|
|
0
|
|
],
|
|
'liberation sans narrow': [
|
|
0.9628,
|
|
0.2407,
|
|
0
|
|
],
|
|
'symbol': [
|
|
1.043,
|
|
0.3209,
|
|
0
|
|
],
|
|
'nanummyeongjo': [
|
|
0.9227,
|
|
0.2407,
|
|
0
|
|
],
|
|
'untitled1': [
|
|
0.682,
|
|
0.5616,
|
|
0
|
|
],
|
|
'lohit gujarati': [
|
|
0.9628,
|
|
0.4012,
|
|
0
|
|
],
|
|
'liberation mono': [
|
|
0.8424,
|
|
0.3209,
|
|
0
|
|
],
|
|
'kacstart': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'mallige': [
|
|
1.0029,
|
|
0.682,
|
|
0
|
|
],
|
|
'bitstream charter': [
|
|
1.0029,
|
|
0.2407,
|
|
0
|
|
],
|
|
'nanumgothic': [
|
|
0.9227,
|
|
0.2407,
|
|
0
|
|
],
|
|
'liberation serif': [
|
|
0.9227,
|
|
0.2407,
|
|
0
|
|
],
|
|
'dejavu sans condensed': [
|
|
0.9628,
|
|
0.2407,
|
|
0
|
|
],
|
|
'ubuntu': [
|
|
0.9628,
|
|
0.2006,
|
|
0
|
|
],
|
|
'courier 10 pitch': [
|
|
0.8825,
|
|
0.3209,
|
|
0
|
|
],
|
|
'nimbus sans l': [
|
|
0.9628,
|
|
0.3209,
|
|
0
|
|
],
|
|
'takaopgothic': [
|
|
0.8825,
|
|
0.2006,
|
|
0
|
|
],
|
|
'wenquanyi micro hei mono': [
|
|
0.9628,
|
|
0.2407,
|
|
0
|
|
],
|
|
'dejavu sans': [
|
|
0.9628,
|
|
0.2407,
|
|
0
|
|
],
|
|
'kedage': [
|
|
1.0029,
|
|
0.682,
|
|
0
|
|
],
|
|
'kinnari': [
|
|
1.3238,
|
|
0.5215,
|
|
0
|
|
],
|
|
'tlwgmono': [
|
|
0.8825,
|
|
0.4012,
|
|
0
|
|
],
|
|
'standard symbols l': [
|
|
1.043,
|
|
0.3209,
|
|
0
|
|
],
|
|
'lohit punjabi': [
|
|
1.2035,
|
|
0.682,
|
|
0
|
|
],
|
|
'nimbus mono l': [
|
|
0.8424,
|
|
0.2808,
|
|
0
|
|
],
|
|
'rachana': [
|
|
0.682,
|
|
0.5616,
|
|
0
|
|
],
|
|
'waree': [
|
|
1.2436,
|
|
0.4413,
|
|
0
|
|
],
|
|
'kacstposter': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'khmer os': [
|
|
1.2837,
|
|
0.7622,
|
|
0
|
|
],
|
|
'freesans': [
|
|
1.0029,
|
|
0.3209,
|
|
0
|
|
],
|
|
'gargi': [
|
|
0.9628,
|
|
0.2808,
|
|
0
|
|
],
|
|
'nimbus roman no9 l': [
|
|
0.9628,
|
|
0.3209,
|
|
0
|
|
],
|
|
'dejavu serif': [
|
|
0.9628,
|
|
0.2407,
|
|
0
|
|
],
|
|
'wenquanyi micro hei': [
|
|
0.9628,
|
|
0.2407,
|
|
0
|
|
],
|
|
'ubuntu light': [
|
|
0.9628,
|
|
0.2006,
|
|
0
|
|
],
|
|
'tlwgtypewriter': [
|
|
0.9227,
|
|
0.4012,
|
|
0
|
|
],
|
|
'kacstpen': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'tlwg typo': [
|
|
0.8825,
|
|
0.4012,
|
|
0
|
|
],
|
|
'mukti narrow': [
|
|
1.2837,
|
|
0.4413,
|
|
0
|
|
],
|
|
'ubuntu mono': [
|
|
0.8424,
|
|
0.2006,
|
|
0
|
|
],
|
|
'lohit bengali': [
|
|
1.0029,
|
|
0.4413,
|
|
0
|
|
],
|
|
'liberation sans': [
|
|
0.9227,
|
|
0.2407,
|
|
0
|
|
],
|
|
'unbatang': [
|
|
1.0029,
|
|
0.2808,
|
|
0
|
|
],
|
|
'kacstdecorative': [
|
|
1.1232,
|
|
0.5215,
|
|
0
|
|
],
|
|
'khmer os system': [
|
|
1.2436,
|
|
0.6017,
|
|
0
|
|
],
|
|
'saab': [
|
|
1.0029,
|
|
0.682,
|
|
0
|
|
],
|
|
'kacsttitle': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'mukti narrow bold': [
|
|
1.2837,
|
|
0.4413,
|
|
0
|
|
],
|
|
'lohit hindi': [
|
|
1.0029,
|
|
0.5215,
|
|
0
|
|
],
|
|
'kacstqurn': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'urw bookman l': [
|
|
0.9628,
|
|
0.2808,
|
|
0
|
|
],
|
|
'kacstnaskh': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'kacstscreen': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
],
|
|
'pothana2000': [
|
|
0.8825,
|
|
0.8424,
|
|
0
|
|
],
|
|
'ungraphic': [
|
|
1.0029,
|
|
0.2808,
|
|
0
|
|
],
|
|
'lohit tamil': [
|
|
0.8825,
|
|
0.361,
|
|
0
|
|
],
|
|
'kacstbook': [
|
|
1.0831,
|
|
0.5215,
|
|
0
|
|
]
|
|
};
|
|
DEVICE_FONT_METRICS_MAC.__proto__ = DEVICE_FONT_METRICS_WIN;
|
|
DEVICE_FONT_METRICS_LINUX.__proto__ = DEVICE_FONT_METRICS_MAC;
|
|
}
|
|
var StaticTextDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.text.StaticText',
|
|
initialize: function () {
|
|
var s = this.symbol;
|
|
if (s) {
|
|
this.draw = s.draw;
|
|
}
|
|
},
|
|
get text() {
|
|
return this._text;
|
|
},
|
|
set text(val) {
|
|
this._text = val;
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
text: desc(def, 'text')
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var StyleSheetDefinition = function () {
|
|
return {
|
|
__class__: 'flash.text.StyleSheet',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
_update: function _update() {
|
|
somewhatImplemented('StyleSheet._update');
|
|
},
|
|
_parseCSSInternal: function _parseCSSInternal(cssText) {
|
|
somewhatImplemented('StyleSheet._parseCSSInternal');
|
|
return null;
|
|
},
|
|
_parseCSSFontFamily: function _parseCSSFontFamily(fontFamily) {
|
|
notImplemented('StyleSheet._parseCSSFontFamily');
|
|
},
|
|
_parseColor: function _parseColor(color) {
|
|
notImplemented('StyleSheet._parseColor');
|
|
},
|
|
_styles: {
|
|
get: function _styles() {
|
|
return this.__styles;
|
|
},
|
|
set: function _styles(styles) {
|
|
somewhatImplemented('StyleSheet._styles');
|
|
this.__styles = styles;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var TextFieldDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.text.TextField',
|
|
initialize: function () {
|
|
this._bbox = {
|
|
xMin: 0,
|
|
yMin: 0,
|
|
xMax: 2000,
|
|
yMax: 2000
|
|
};
|
|
var initialFormat = {
|
|
align: 'LEFT',
|
|
face: 'serif',
|
|
size: 12,
|
|
letterspacing: 0,
|
|
kerning: 0,
|
|
color: 0,
|
|
leading: 0
|
|
};
|
|
this._content = new TextFieldContent(initialFormat);
|
|
this._type = 'dynamic';
|
|
this._embedFonts = false;
|
|
this._selectable = true;
|
|
this._autoSize = 'none';
|
|
this._scrollV = 1;
|
|
this._maxScrollV = 1;
|
|
this._bottomScrollV = 1;
|
|
this._drawingOffsetH = 0;
|
|
this._background = false;
|
|
this._border = false;
|
|
this._backgroundColor = 16777215;
|
|
this._backgroundColorStr = '#ffffff';
|
|
this._borderColor = 0;
|
|
this._borderColorStr = '#000000';
|
|
var s = this.symbol;
|
|
if (!s) {
|
|
this._currentTransform.tx -= 40;
|
|
this._currentTransform.ty -= 40;
|
|
this._content.resolveFont(initialFormat, false);
|
|
this.text = '';
|
|
return;
|
|
}
|
|
var tag = s.tag;
|
|
var bbox = tag.bbox;
|
|
this._currentTransform.tx += bbox.xMin;
|
|
this._currentTransform.ty += bbox.yMin;
|
|
this._bbox.xMax = bbox.xMax - bbox.xMin;
|
|
this._bbox.yMax = bbox.yMax - bbox.yMin;
|
|
if (tag.hasLayout) {
|
|
initialFormat.size = tag.fontHeight / 20;
|
|
initialFormat.leading = (tag.leading | 0) / 20;
|
|
}
|
|
if (tag.hasColor) {
|
|
initialFormat.color = rgbaObjToStr(tag.color);
|
|
}
|
|
if (tag.hasFont) {
|
|
var font = FontDefinition.getFontByUniqueName(tag.font);
|
|
initialFormat.font = font;
|
|
initialFormat.face = font._fontName;
|
|
initialFormat.bold = font.symbol.bold;
|
|
initialFormat.italic = font.symbol.italic;
|
|
initialFormat.str = this._content.makeFormatString(initialFormat);
|
|
}
|
|
this._content.multiline = !(!tag.multiline);
|
|
this._content.wordWrap = !(!tag.wordWrap);
|
|
this._embedFonts = !(!tag.useOutlines);
|
|
this._selectable = !tag.noSelect;
|
|
this._border = !(!tag.border);
|
|
switch (tag.align) {
|
|
case 1:
|
|
initialFormat.align = 'right';
|
|
break;
|
|
case 2:
|
|
initialFormat.align = 'center';
|
|
break;
|
|
case 3:
|
|
initialFormat.align = 'justified';
|
|
break;
|
|
default:
|
|
}
|
|
if (tag.initialText) {
|
|
if (tag.html) {
|
|
this.htmlText = tag.initialText;
|
|
} else {
|
|
this.text = tag.initialText;
|
|
}
|
|
} else {
|
|
this.text = '';
|
|
}
|
|
},
|
|
_getAS2Object: function () {
|
|
if (!this.$as2Object) {
|
|
new avm1lib.AS2TextField(this);
|
|
}
|
|
return this.$as2Object;
|
|
},
|
|
replaceText: function (begin, end, str) {
|
|
var text = this._content.text;
|
|
this.text = text.substring(0, begin) + str + text.substring(end);
|
|
},
|
|
draw: function (ctx, ratio, colorTransform) {
|
|
this.ensureDimensions();
|
|
var bounds = this._bbox;
|
|
var width = bounds.xMax / 20;
|
|
var height = bounds.yMax / 20;
|
|
if (width <= 0 || height <= 0) {
|
|
return;
|
|
}
|
|
ctx.save();
|
|
ctx.beginPath();
|
|
ctx.rect(0, 0, width + 1, height + 1);
|
|
ctx.clip();
|
|
if (this._background) {
|
|
colorTransform.setFillStyle(ctx, this._backgroundColorStr);
|
|
ctx.fill();
|
|
}
|
|
if (this._border) {
|
|
colorTransform.setStrokeStyle(ctx, this._borderColorStr);
|
|
ctx.lineCap = 'square';
|
|
ctx.lineWidth = 1;
|
|
ctx.strokeRect(0.5, 0.5, width | 0, height | 0);
|
|
}
|
|
ctx.closePath();
|
|
if (this._content.lines.length === 0) {
|
|
ctx.restore();
|
|
return;
|
|
}
|
|
ctx.translate(2, 2);
|
|
ctx.save();
|
|
colorTransform.setAlpha(ctx);
|
|
var runs = this._content._textRuns;
|
|
var offsetY = this._content.lines[this._scrollV - 1].y;
|
|
for (var i = 0; i < runs.length; i++) {
|
|
var run = runs[i];
|
|
if (run.type === 'f') {
|
|
ctx.restore();
|
|
ctx.font = run.format.str;
|
|
colorTransform.setFillStyle(ctx, run.format.color);
|
|
ctx.save();
|
|
colorTransform.setAlpha(ctx);
|
|
} else {
|
|
if (run.y < offsetY) {
|
|
continue;
|
|
}
|
|
ctx.fillText(run.text, run.x - this._drawingOffsetH, run.y - offsetY);
|
|
}
|
|
}
|
|
ctx.restore();
|
|
ctx.restore();
|
|
},
|
|
invalidateDimensions: function () {
|
|
this._invalidate();
|
|
this._invalidateBounds();
|
|
this._dimensionsValid = false;
|
|
},
|
|
ensureDimensions: function () {
|
|
if (this._dimensionsValid) {
|
|
return;
|
|
}
|
|
var bounds = this._bbox;
|
|
var combinedAlign = this._content.calculateMetrics(bounds, this._embedFonts);
|
|
this._scrollV = 1;
|
|
this._maxScrollV = 1;
|
|
this._bottomScrollV = 1;
|
|
var autoSize = this._autoSize;
|
|
if (autoSize === 'none') {
|
|
var maxVisibleY = (bounds.yMax - 80) / 20;
|
|
if (this._content.textHeight > maxVisibleY) {
|
|
var lines = this._content.lines;
|
|
for (var i = 0; i < lines.length; i++) {
|
|
var line = lines[i];
|
|
if (line.y + line.height > maxVisibleY) {
|
|
this._maxScrollV = i + 1;
|
|
this._bottomScrollV = i === 0 ? 1 : i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
var width = Math.max(bounds.xMax / 20 - 4, 1);
|
|
var targetWidth = this._content.textWidth;
|
|
var align = combinedAlign;
|
|
var diffX = 0;
|
|
if (align !== 'mixed') {
|
|
switch (autoSize) {
|
|
case 'left':
|
|
break;
|
|
case 'center':
|
|
diffX = width - targetWidth >> 1;
|
|
break;
|
|
case 'right':
|
|
diffX = width - targetWidth;
|
|
}
|
|
if (align === 'left') {
|
|
this._drawingOffsetH = 0;
|
|
} else {
|
|
var offset;
|
|
switch (autoSize) {
|
|
case 'left':
|
|
offset = width - targetWidth;
|
|
break;
|
|
case 'center':
|
|
offset = diffX << 1;
|
|
break;
|
|
case 'right':
|
|
offset = diffX;
|
|
break;
|
|
}
|
|
if (align === 'center') {
|
|
offset >>= 1;
|
|
}
|
|
this._drawingOffsetH = offset;
|
|
}
|
|
this._invalidateTransform();
|
|
this._currentTransform.tx += diffX * 20 | 0;
|
|
bounds.xMax = (targetWidth * 20 | 0) + 80;
|
|
}
|
|
bounds.yMax = (this._content.textHeight * 20 | 0) + 80;
|
|
console.log(bounds.yMax);
|
|
this._invalidateBounds();
|
|
}
|
|
this._dimensionsValid = true;
|
|
},
|
|
get text() {
|
|
return this._content.text;
|
|
},
|
|
set text(val) {
|
|
this._content.text = val;
|
|
this.invalidateDimensions();
|
|
},
|
|
get htmlText() {
|
|
return this._content.htmlText;
|
|
},
|
|
set htmlText(val) {
|
|
this._content.htmlText = val;
|
|
this.invalidateDimensions();
|
|
},
|
|
get defaultTextFormat() {
|
|
var format = this._content.defaultTextFormat;
|
|
return new flash.text.TextFormat().fromObject(format);
|
|
},
|
|
set defaultTextFormat(val) {
|
|
this._content.defaultTextFormat = val.toObject();
|
|
this.invalidateDimensions();
|
|
},
|
|
getTextFormat: function (beginIndex, endIndex) {
|
|
return this.defaultTextFormat;
|
|
},
|
|
setTextFormat: function (format, beginIndex, endIndex) {
|
|
this.defaultTextFormat = format;
|
|
if (this.text === this.htmlText) {
|
|
this.text = this.text;
|
|
}
|
|
this.invalidateDimensions();
|
|
},
|
|
get x() {
|
|
this.ensureDimensions();
|
|
return this._currentTransform.tx;
|
|
},
|
|
set x(val) {
|
|
if (val === this._currentTransform.tx) {
|
|
return;
|
|
}
|
|
this._invalidate();
|
|
this._invalidateBounds();
|
|
this._invalidateTransform();
|
|
this._currentTransform.tx = val;
|
|
},
|
|
get width() {
|
|
this.ensureDimensions();
|
|
return this._bbox.xMax;
|
|
},
|
|
set width(value) {
|
|
if (value < 0) {
|
|
return;
|
|
}
|
|
this._bbox.xMax = value;
|
|
this.invalidateDimensions();
|
|
},
|
|
get height() {
|
|
this.ensureDimensions();
|
|
return this._bbox.yMax;
|
|
},
|
|
set height(value) {
|
|
if (value < 0) {
|
|
return;
|
|
}
|
|
this._bbox.yMax = value;
|
|
this._invalidate();
|
|
},
|
|
_getContentBounds: function () {
|
|
this.ensureDimensions();
|
|
return this._bbox;
|
|
},
|
|
_getRegion: function getRegion(targetCoordSpace) {
|
|
return this._getTransformedRect(this._getContentBounds(), targetCoordSpace);
|
|
},
|
|
getLineMetrics: function (lineIndex) {
|
|
this.ensureDimensions();
|
|
if (lineIndex < 0 || lineIndex >= this._content.lines.length) {
|
|
throwError('RangeError', Errors.ParamRangeError);
|
|
}
|
|
var line = this._content.lines[lineIndex];
|
|
var format = line.largestFormat;
|
|
var metrics = format.font._metrics;
|
|
var size = format.size;
|
|
var ascent = metrics.ascent * size + 0.49999 | 0;
|
|
var descent = metrics.descent * size + 0.49999 | 0;
|
|
var leading = metrics.leading * size + 0.49999 + line.leading | 0;
|
|
return new flash.text.TextLineMetrics(line.x + 2, line.width, line.height, ascent, descent, leading);
|
|
},
|
|
getCharBoundaries: function getCharBoundaries(index) {
|
|
somewhatImplemented('TextField.getCharBoundaries');
|
|
return new flash.geom.Rectangle(0, 0, 0, 0);
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
text: desc(def, 'text'),
|
|
defaultTextFormat: desc(def, 'defaultTextFormat'),
|
|
draw: def.draw,
|
|
htmlText: desc(def, 'htmlText'),
|
|
replaceText: def.replaceText,
|
|
getTextFormat: def.getTextFormat,
|
|
setTextFormat: def.setTextFormat,
|
|
getCharBoundaries: def.getCharBoundaries,
|
|
autoSize: {
|
|
get: function autoSize() {
|
|
return this._autoSize;
|
|
},
|
|
set: function autoSize(value) {
|
|
if (this._autoSize === value) {
|
|
return;
|
|
}
|
|
this._autoSize = value;
|
|
this.invalidateDimensions();
|
|
}
|
|
},
|
|
multiline: {
|
|
get: function multiline() {
|
|
return this._content.multiline;
|
|
},
|
|
set: function multiline(value) {
|
|
if (this._content.multiline === value) {
|
|
return;
|
|
}
|
|
this._content.multiline = value;
|
|
this.invalidateDimensions();
|
|
}
|
|
},
|
|
textColor: {
|
|
get: function textColor() {
|
|
return this._content.textColor;
|
|
},
|
|
set: function textColor(value) {
|
|
if (this._content.textColor === value) {
|
|
return;
|
|
}
|
|
this._content.textColor = value;
|
|
this._invalidate();
|
|
}
|
|
},
|
|
selectable: {
|
|
get: function selectable() {
|
|
return this._selectable;
|
|
},
|
|
set: function selectable(value) {
|
|
somewhatImplemented('TextField.selectable');
|
|
this._selectable = value;
|
|
}
|
|
},
|
|
wordWrap: {
|
|
get: function wordWrap() {
|
|
return this._content.wordWrap;
|
|
},
|
|
set: function wordWrap(value) {
|
|
if (this._content.wordWrap === value) {
|
|
return;
|
|
}
|
|
this._content.wordWrap = value;
|
|
this.invalidateDimensions();
|
|
}
|
|
},
|
|
textHeight: {
|
|
get: function textHeight() {
|
|
this.ensureDimensions();
|
|
return this._content.textHeight;
|
|
}
|
|
},
|
|
textWidth: {
|
|
get: function textWidth() {
|
|
this.ensureDimensions();
|
|
return this._content.textWidth;
|
|
}
|
|
},
|
|
length: {
|
|
get: function length() {
|
|
return this.text.length;
|
|
}
|
|
},
|
|
numLines: {
|
|
get: function numLines() {
|
|
this.ensureDimensions();
|
|
return this._content.lines.length;
|
|
}
|
|
},
|
|
getLineMetrics: function (lineIndex) {
|
|
return this.getLineMetrics(lineIndex);
|
|
},
|
|
setSelection: function (beginIndex, endIndex) {
|
|
somewhatImplemented('TextField.setSelection');
|
|
},
|
|
scrollV: {
|
|
get: function scrollV() {
|
|
return this._scrollV;
|
|
},
|
|
set: function scrollV(value) {
|
|
this.ensureDimensions();
|
|
value = Math.max(1, Math.min(this._maxScrollV, value));
|
|
this._scrollV = value;
|
|
}
|
|
},
|
|
bottomScrollV: {
|
|
get: function bottomScrollV() {
|
|
this.ensureDimensions();
|
|
if (this._scrollV === 1) {
|
|
return this._bottomScrollV;
|
|
}
|
|
var maxVisibleY = (this._bbox.yMax - 80) / 20;
|
|
var lines = this._content.lines;
|
|
var offsetY = lines[this._scrollV - 1].y;
|
|
for (var i = this._bottomScrollV; i < lines.length; i++) {
|
|
var line = lines[i];
|
|
if (line.y + line.height + offsetY > maxVisibleY) {
|
|
return i + 1;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
maxScrollV: {
|
|
get: function maxScrollV() {
|
|
this.ensureDimensions();
|
|
return this._maxScrollV;
|
|
}
|
|
},
|
|
maxScrollH: {
|
|
get: function maxScrollH() {
|
|
this.ensureDimensions();
|
|
return Math.max(this._content.textWidth - this._bbox.xMax / 20 + 4, 0);
|
|
}
|
|
},
|
|
background: {
|
|
get: function background() {
|
|
return this._background;
|
|
},
|
|
set: function background(value) {
|
|
if (this._background === value) {
|
|
return;
|
|
}
|
|
this._background = value;
|
|
this._invalidate();
|
|
}
|
|
},
|
|
backgroundColor: {
|
|
get: function backgroundColor() {
|
|
return this._backgroundColor;
|
|
},
|
|
set: function backgroundColor(value) {
|
|
if (this._backgroundColor === value) {
|
|
return;
|
|
}
|
|
this._backgroundColor = value;
|
|
this._backgroundColorStr = rgbIntAlphaToStr(value, 1);
|
|
if (this._background) {
|
|
this._invalidate();
|
|
}
|
|
}
|
|
},
|
|
border: {
|
|
get: function border() {
|
|
return this._border;
|
|
},
|
|
set: function border(value) {
|
|
if (this._border === value) {
|
|
return;
|
|
}
|
|
this._border = value;
|
|
this._invalidate();
|
|
}
|
|
},
|
|
borderColor: {
|
|
get: function borderColor() {
|
|
return this._borderColor;
|
|
},
|
|
set: function borderColor(value) {
|
|
if (this._borderColor === value) {
|
|
return;
|
|
}
|
|
this._borderColor = value;
|
|
this._borderColorStr = rgbIntAlphaToStr(value, 1);
|
|
if (this._border) {
|
|
this._invalidate();
|
|
}
|
|
}
|
|
},
|
|
type: {
|
|
get: function borderColor() {
|
|
return this._type;
|
|
},
|
|
set: function borderColor(value) {
|
|
somewhatImplemented('TextField.type');
|
|
this._type = value;
|
|
}
|
|
},
|
|
embedFonts: {
|
|
get: function embedFonts() {
|
|
return this._embedFonts;
|
|
},
|
|
set: function embedFonts(value) {
|
|
this.invalidateDimensions();
|
|
this._embedFonts = value;
|
|
}
|
|
},
|
|
condenseWhite: {
|
|
get: function condenseWhite() {
|
|
return this._content.condenseWhite;
|
|
},
|
|
set: function condenseWhite(value) {
|
|
somewhatImplemented('TextField.condenseWhite');
|
|
this._content.condenseWhite = value;
|
|
}
|
|
},
|
|
sharpness: {
|
|
get: function sharpness() {
|
|
return this._sharpness;
|
|
},
|
|
set: function sharpness(value) {
|
|
somewhatImplemented('TextField.sharpness');
|
|
this._sharpness = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
function TextFieldContent(initialFormat) {
|
|
this.defaultTextFormat = initialFormat;
|
|
this.textWidth = 0;
|
|
this.textHeight = 0;
|
|
this.condenseWhite = false;
|
|
this.wordWrap = false;
|
|
this.multiline = false;
|
|
this.textColor = null;
|
|
this._text = '';
|
|
this._htmlText = '';
|
|
this._createTrunk();
|
|
this._textRuns = null;
|
|
this._htmlParser = document.createElement('p');
|
|
this._measureCtx = document.createElement('canvas').getContext('2d');
|
|
}
|
|
TextFieldContent.knownNodeTypes = {
|
|
'BR': true,
|
|
'LI': true,
|
|
'P': true,
|
|
'B': true,
|
|
'I': true,
|
|
'FONT': true,
|
|
'TEXTFORMAT': true,
|
|
'U': true,
|
|
'A': true,
|
|
'IMG': true,
|
|
'SPAN': true
|
|
};
|
|
TextFieldContent.WRAP_OPPORTUNITIES = {
|
|
' ': true,
|
|
'.': true,
|
|
'-': true,
|
|
'\t': true
|
|
};
|
|
TextFieldContent.TextLine = function (y) {
|
|
this.x = 0;
|
|
this.width = 0;
|
|
this.y = y;
|
|
this.height = 0;
|
|
this.leading = 0;
|
|
this.runs = [];
|
|
this.largestFormat = null;
|
|
};
|
|
TextFieldContent.prototype = {
|
|
get text() {
|
|
return this._text;
|
|
},
|
|
set text(val) {
|
|
val = val + '';
|
|
if (this._text === val) {
|
|
return;
|
|
}
|
|
var lines = [];
|
|
var lineOffset = 0;
|
|
for (var index = 0; index < val.length;) {
|
|
var char = val[index];
|
|
if (char === '\r' || char === '\n') {
|
|
lines.push(val.substring(lineOffset, index));
|
|
lineOffset = index;
|
|
if (char === '\r' && val[index + 1] === '\n') {
|
|
index++;
|
|
}
|
|
}
|
|
index++;
|
|
}
|
|
lines.push(val.substring(lineOffset, index));
|
|
this._createTrunk();
|
|
this._text = val;
|
|
this._htmlText = val;
|
|
this._tree.children[0].children[0] = {
|
|
type: 'plain-text',
|
|
lines: lines
|
|
};
|
|
},
|
|
get htmlText() {
|
|
return this._htmlText;
|
|
},
|
|
set htmlText(val) {
|
|
if (this._htmlText === val) {
|
|
return;
|
|
}
|
|
this.defaultTextFormat.bold = false;
|
|
this.defaultTextFormat.italic = false;
|
|
this._parseHtml(val);
|
|
},
|
|
calculateMetrics: function (bounds, embedFonts) {
|
|
var initialFormat = this.defaultTextFormat;
|
|
this.resolveFont(initialFormat, embedFonts);
|
|
this.lines = [];
|
|
this._textRuns = [
|
|
{
|
|
type: 'f',
|
|
format: initialFormat
|
|
}
|
|
];
|
|
var width = Math.max(bounds.xMax / 20 - 4, 1);
|
|
var height = Math.max(bounds.yMax / 20 - 4, 1);
|
|
var state = {
|
|
ctx: this._measureCtx,
|
|
w: width,
|
|
h: height,
|
|
maxLineWidth: 0,
|
|
formats: [
|
|
initialFormat
|
|
],
|
|
currentFormat: initialFormat,
|
|
line: new TextFieldContent.TextLine(0),
|
|
wordWrap: this.wordWrap,
|
|
combinedAlign: null,
|
|
textColor: this.textColor,
|
|
embedFonts: embedFonts
|
|
};
|
|
this._collectRuns(state, this._tree);
|
|
this._finishLine(state, false);
|
|
this.textWidth = state.maxLineWidth | 0;
|
|
this.textHeight = state.line.y | 0;
|
|
return state.combinedAlign;
|
|
},
|
|
makeFormatString: function (format) {
|
|
var boldItalic = '';
|
|
if (format.italic) {
|
|
boldItalic += 'italic';
|
|
}
|
|
if (format.bold) {
|
|
boldItalic += ' bold';
|
|
}
|
|
return boldItalic + ' ' + format.size + 'px ' + (format.font._uniqueName || format.font._fontName);
|
|
},
|
|
resolveFont: function (format, embedded) {
|
|
var face = format.face.toLowerCase();
|
|
if (face === '_sans') {
|
|
face = 'sans-serif';
|
|
} else if (face === '_serif') {
|
|
face = 'serif';
|
|
} else if (face === '_typewriter') {
|
|
face = 'monospace';
|
|
}
|
|
var style;
|
|
if (format.bold) {
|
|
if (format.italic) {
|
|
style = 'boldItalic';
|
|
} else {
|
|
style = 'bold';
|
|
}
|
|
} else if (format.italic) {
|
|
style = 'italic';
|
|
} else {
|
|
style = 'regular';
|
|
}
|
|
var font = FontDefinition.getFont(face, style, embedded);
|
|
format.font = font;
|
|
},
|
|
_parseHtml: function (val) {
|
|
this._htmlParser.innerHTML = val;
|
|
var rootElement = this._htmlParser.childNodes.length !== 1 ? this._htmlParser : this._htmlParser.childNodes[0];
|
|
this._text = '';
|
|
this._htmlText = val;
|
|
this._createTrunk();
|
|
if (rootElement.nodeType === 3) {
|
|
this._convertNode(rootElement, this._tree.children[0].children);
|
|
}
|
|
var initialNodeList = [
|
|
rootElement
|
|
];
|
|
var attributes;
|
|
var format;
|
|
var key;
|
|
if (initialNodeList.length == 1 && rootElement.localName.toUpperCase() == 'P') {
|
|
attributes = this._extractAttributes(rootElement);
|
|
format = this._tree.format;
|
|
for (key in attributes) {
|
|
format[key] = attributes[key];
|
|
}
|
|
initialNodeList = rootElement.childNodes;
|
|
rootElement = rootElement.childNodes[0];
|
|
}
|
|
if (initialNodeList.length == 1 && rootElement.localName.toUpperCase() == 'FONT') {
|
|
attributes = this._extractAttributes(rootElement);
|
|
format = this._tree.children[0].format;
|
|
for (key in attributes) {
|
|
format[key] = attributes[key];
|
|
}
|
|
initialNodeList = rootElement.childNodes;
|
|
}
|
|
this._convertNodeList(initialNodeList, this._tree.children[0].children);
|
|
},
|
|
_createTrunk: function () {
|
|
var initialFormat = this.defaultTextFormat;
|
|
this._tree = {
|
|
type: 'SPAN',
|
|
format: {
|
|
ALIGN: initialFormat.align
|
|
},
|
|
children: []
|
|
};
|
|
var fontAttributes = {
|
|
FACE: initialFormat.face,
|
|
LETTERSPACING: initialFormat.letterSpacing,
|
|
KERNING: initialFormat.kerning,
|
|
LEADING: initialFormat.leading,
|
|
COLOR: initialFormat.color
|
|
};
|
|
this._tree.children[0] = {
|
|
type: 'FONT',
|
|
format: fontAttributes,
|
|
children: []
|
|
};
|
|
},
|
|
_convertNode: function (input, destinationList) {
|
|
if (!(input.nodeType === 1 || input.nodeType === 3) || input.prefix) {
|
|
return;
|
|
}
|
|
var node;
|
|
if (input.nodeType === 3) {
|
|
var text = input.textContent;
|
|
node = {
|
|
type: 'text',
|
|
text: text,
|
|
format: null,
|
|
children: null
|
|
};
|
|
this._text += text;
|
|
destinationList.push(node);
|
|
return;
|
|
}
|
|
var nodeType = input.localName.toUpperCase();
|
|
if (!TextFieldContent.knownNodeTypes[nodeType] || this.multiline === false && (nodeType === 'P' || nodeType === 'BR')) {
|
|
if (nodeType === 'SBR') {
|
|
destinationList.push({
|
|
type: 'BR',
|
|
text: null,
|
|
format: null,
|
|
children: null
|
|
});
|
|
}
|
|
this._convertNodeList(input.childNodes, destinationList);
|
|
return;
|
|
}
|
|
node = {
|
|
type: nodeType,
|
|
text: null,
|
|
format: this._extractAttributes(input),
|
|
children: []
|
|
};
|
|
this._convertNodeList(input.childNodes, node.children);
|
|
destinationList.push(node);
|
|
},
|
|
_convertNodeList: function (from, to) {
|
|
var childCount = from.length;
|
|
for (var i = 0; i < childCount; i++) {
|
|
this._convertNode(from[i], to);
|
|
}
|
|
},
|
|
_extractAttributes: function (node) {
|
|
var attributesList = node.attributes;
|
|
var attributesMap = {};
|
|
for (var i = 0; i < attributesList.length; i++) {
|
|
var attr = attributesList[i];
|
|
if (attr.prefix) {
|
|
continue;
|
|
}
|
|
attributesMap[attr.localName.toUpperCase()] = attr.value;
|
|
}
|
|
return attributesMap;
|
|
},
|
|
_collectRuns: function (state, node) {
|
|
var formatNode = false;
|
|
var blockNode = false;
|
|
switch (node.type) {
|
|
case 'plain-text':
|
|
var lines = node.lines;
|
|
for (var i = 0; i < lines.length; i++) {
|
|
this._addRunsForText(state, lines[i]);
|
|
if (i < lines.length - 1) {
|
|
this._finishLine(state, true);
|
|
}
|
|
}
|
|
return;
|
|
case 'text':
|
|
this._addRunsForText(state, node.text);
|
|
return;
|
|
case 'BR':
|
|
this._finishLine(state, true);
|
|
return;
|
|
case 'LI':
|
|
case 'P':
|
|
this._finishLine(state, false);
|
|
this._pushFormat(state, node);
|
|
blockNode = true;
|
|
break;
|
|
case 'B':
|
|
case 'I':
|
|
case 'FONT':
|
|
case 'TEXTFORMAT':
|
|
this._pushFormat(state, node);
|
|
formatNode = true;
|
|
break;
|
|
case 'U':
|
|
case 'A':
|
|
case 'IMG':
|
|
case 'SPAN':
|
|
default:
|
|
}
|
|
for (var i = 0; i < node.children.length; i++) {
|
|
var child = node.children[i];
|
|
this._collectRuns(state, child);
|
|
}
|
|
if (formatNode) {
|
|
this._popFormat(state);
|
|
}
|
|
if (blockNode) {
|
|
this._finishLine(state, true);
|
|
}
|
|
},
|
|
_addRunsForText: function (state, text) {
|
|
if (!text) {
|
|
return;
|
|
}
|
|
if (!state.wordWrap) {
|
|
this._addTextRun(state, text, state.ctx.measureText(text).width);
|
|
return;
|
|
}
|
|
while (text.length) {
|
|
var width = state.ctx.measureText(text).width;
|
|
var availableWidth = state.w - state.line.width;
|
|
if (availableWidth <= 0) {
|
|
this._finishLine(state, false);
|
|
availableWidth = state.w - state.line.width;
|
|
}
|
|
if (width <= availableWidth) {
|
|
this._addTextRun(state, text, width);
|
|
break;
|
|
} else {
|
|
var offset = text.length / width * availableWidth | 0;
|
|
while (state.ctx.measureText(text.substr(0, offset)).width < availableWidth && offset < text.length) {
|
|
offset++;
|
|
}
|
|
var wrapOffset = offset;
|
|
while (wrapOffset > -1) {
|
|
if (TextFieldContent.WRAP_OPPORTUNITIES[text[wrapOffset]]) {
|
|
wrapOffset++;
|
|
break;
|
|
}
|
|
wrapOffset--;
|
|
}
|
|
if (wrapOffset === -1) {
|
|
if (state.line.width > 0) {
|
|
this._finishLine(state, false);
|
|
continue;
|
|
}
|
|
while (state.ctx.measureText(text.substr(0, offset)).width > availableWidth) {
|
|
offset--;
|
|
}
|
|
if (offset === 0) {
|
|
offset = 1;
|
|
}
|
|
wrapOffset = offset;
|
|
}
|
|
var runText = text.substr(0, wrapOffset);
|
|
width = state.ctx.measureText(runText).width;
|
|
this._addTextRun(state, runText, width);
|
|
if (state.wordWrap) {
|
|
this._finishLine(state, false);
|
|
}
|
|
text = text.substr(wrapOffset);
|
|
}
|
|
}
|
|
},
|
|
_addTextRun: function (state, text, width) {
|
|
if (text.length === 0) {
|
|
return;
|
|
}
|
|
var line = state.line;
|
|
var format = state.currentFormat;
|
|
var size = format.size;
|
|
var run = {
|
|
type: 't',
|
|
text: text,
|
|
x: line.width
|
|
};
|
|
this._textRuns.push(run);
|
|
state.line.runs.push(run);
|
|
line.width += width | 0;
|
|
if (line.leading === 0 && format.leading > line.leading) {
|
|
line.leading = format.leading;
|
|
}
|
|
if (!line.largestFormat || size > line.largestFormat.size) {
|
|
line.largestFormat = format;
|
|
}
|
|
},
|
|
_finishLine: function (state, forceNewline) {
|
|
var line = state.line;
|
|
if (line.runs.length === 0) {
|
|
if (forceNewline) {
|
|
var format = state.currentFormat;
|
|
state.line.y += format.font._metrics.height * format.size + format.leading | 0;
|
|
}
|
|
return;
|
|
}
|
|
var runs = line.runs;
|
|
var format = line.largestFormat;
|
|
var baselinePos = line.y + format.font._metrics.ascent * format.size;
|
|
for (var i = runs.length; i--;) {
|
|
runs[i].y = baselinePos;
|
|
}
|
|
var align = (state.currentFormat.align || '').toLowerCase();
|
|
if (state.combinedAlign === null) {
|
|
state.combinedAlign = align;
|
|
} else if (state.combinedAlign !== align) {
|
|
state.combinedAlign = 'mixed';
|
|
}
|
|
if (align === 'center' || align === 'right') {
|
|
var offset = Math.max(state.w - line.width, 0);
|
|
if (align === 'center') {
|
|
offset >>= 1;
|
|
}
|
|
for (i = runs.length; i--;) {
|
|
runs[i].x += offset;
|
|
}
|
|
}
|
|
line.height = format.font._metrics.height * format.size + line.leading | 0;
|
|
state.maxLineWidth = Math.max(state.maxLineWidth, line.width);
|
|
this.lines.push(line);
|
|
state.line = new TextFieldContent.TextLine(line.y + line.height);
|
|
},
|
|
_pushFormat: function (state, node) {
|
|
var attributes = node.format;
|
|
var format = Object.create(state.formats[state.formats.length - 1]);
|
|
var fontChanged = false;
|
|
switch (node.type) {
|
|
case 'P':
|
|
if (attributes.ALIGN === format.align) {
|
|
return;
|
|
}
|
|
format.align = attributes.ALIGN;
|
|
break;
|
|
case 'B':
|
|
format.bold = true;
|
|
fontChanged = true;
|
|
break;
|
|
case 'I':
|
|
format.italic = true;
|
|
fontChanged = true;
|
|
break;
|
|
case 'FONT':
|
|
if (attributes.COLOR !== undefined) {
|
|
format.color = attributes.COLOR;
|
|
}
|
|
if (attributes.FACE !== undefined) {
|
|
format.face = attributes.FACE;
|
|
fontChanged = true;
|
|
}
|
|
if (attributes.SIZE !== undefined) {
|
|
format.size = parseFloat(attributes.SIZE);
|
|
}
|
|
if (attributes.LETTERSPACING !== undefined) {
|
|
format.letterspacing = parseFloat(attributes.LETTERSPACING);
|
|
}
|
|
if (attributes.KERNING !== undefined) {
|
|
format.kerning = attributes.KERNING && true;
|
|
}
|
|
case 'TEXTFORMAT':
|
|
if (attributes.LEADING !== undefined) {
|
|
format.leading = parseFloat(attributes.LEADING);
|
|
}
|
|
if (attributes.INDENT !== undefined) {
|
|
state.line.x = attributes.INDENT;
|
|
state.line.width += attributes.INDENT | 0;
|
|
}
|
|
break;
|
|
default:
|
|
warning('Unknown format node encountered: ' + node.type);
|
|
return;
|
|
}
|
|
if (state.textColor !== null) {
|
|
format.color = rgbIntAlphaToStr(state.textColor, 1);
|
|
}
|
|
if (fontChanged) {
|
|
this.resolveFont(format, state.embedFonts);
|
|
}
|
|
format.str = this.makeFormatString(format);
|
|
state.formats.push(format);
|
|
this._textRuns.push({
|
|
type: 'f',
|
|
format: format
|
|
});
|
|
state.currentFormat = format;
|
|
state.ctx.font = format.str;
|
|
},
|
|
_popFormat: function (state) {
|
|
state.formats.pop();
|
|
var format = state.currentFormat = state.formats[state.formats.length - 1];
|
|
this._textRuns.push({
|
|
type: 'f',
|
|
format: format
|
|
});
|
|
state.ctx.font = state.str;
|
|
}
|
|
};
|
|
var TextFormatDefinition = function () {
|
|
var measureTextField;
|
|
return {
|
|
__class__: 'flash.text.TextFormat',
|
|
initialize: function () {
|
|
},
|
|
fromObject: function (obj) {
|
|
this._font = obj.face || null;
|
|
this._size = typeof obj.size === 'number' ? obj.size : null;
|
|
this._color = typeof obj.color === 'number' ? obj.color : null;
|
|
this._bold = typeof obj.bold === 'boolean' ? obj.bold : null;
|
|
this._italic = typeof obj.italic === 'boolean' ? obj.italic : null;
|
|
this._underline = typeof obj.underline === 'boolean' ? obj.underline : null;
|
|
this._url = obj.url || null;
|
|
this._target = obj.target || null;
|
|
this._align = obj.align || null;
|
|
this._leftMargin = typeof obj.leftMargin === 'number' ? obj.leftMargin : null;
|
|
this._rightMargin = typeof obj.rightMargin === 'number' ? obj.rightMargin : null;
|
|
this._indent = typeof obj.indent === 'number' ? obj.indent : null;
|
|
this._leading = typeof obj.leading === 'number' ? obj.leading : null;
|
|
return this;
|
|
},
|
|
toObject: function () {
|
|
return {
|
|
face: this._font || 'serif',
|
|
size: this._size || 12,
|
|
color: this._color || 0,
|
|
bold: this._bold || false,
|
|
italic: this._italic || false,
|
|
underline: this._underline || false,
|
|
url: this._url,
|
|
target: this._target,
|
|
align: this._align || 'left',
|
|
leftMargin: this._leftMargin || 0,
|
|
rightMargin: this._rightMargin || 0,
|
|
indent: this._indent || 0,
|
|
leading: this._leading || 0
|
|
};
|
|
},
|
|
as2GetTextExtent: function (text, width) {
|
|
if (!measureTextField) {
|
|
measureTextField = new flash.text.TextField();
|
|
measureTextField._multiline = true;
|
|
}
|
|
if (!isNaN(width) && width > 0) {
|
|
measureTextField.width = width + 4;
|
|
measureTextField._wordWrap = true;
|
|
} else {
|
|
measureTextField._wordWrap = false;
|
|
}
|
|
measureTextField.defaultTextFormat = this;
|
|
measureTextField.text = text;
|
|
measureTextField.ensureDimensions();
|
|
var result = {};
|
|
var textWidth = measureTextField._textWidth;
|
|
var textHeight = measureTextField._textHeight;
|
|
result.asSetPublicProperty('width', textWidth);
|
|
result.asSetPublicProperty('height', textHeight);
|
|
result.asSetPublicProperty('textFieldWidth', textWidth + 4);
|
|
result.asSetPublicProperty('textFieldHeight', textHeight + 4);
|
|
var metrics = measureTextField.getLineMetrics(0);
|
|
result.asSetPublicProperty('ascent', metrics.asGetPublicProperty('ascent'));
|
|
result.asSetPublicProperty('descent', metrics.asGetPublicProperty('descent'));
|
|
return result;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
align: {
|
|
get: function align() {
|
|
return this._align;
|
|
},
|
|
set: function align(value) {
|
|
this._align = value;
|
|
}
|
|
},
|
|
blockIndent: {
|
|
get: function blockIndent() {
|
|
return this._blockIndent;
|
|
},
|
|
set: function blockIndent(value) {
|
|
this._blockIndent = value;
|
|
}
|
|
},
|
|
bold: {
|
|
get: function bold() {
|
|
return this._bold;
|
|
},
|
|
set: function bold(value) {
|
|
this._bold = value;
|
|
}
|
|
},
|
|
bullet: {
|
|
get: function bullet() {
|
|
return this._bullet;
|
|
},
|
|
set: function bullet(value) {
|
|
this._bullet = value;
|
|
}
|
|
},
|
|
color: {
|
|
get: function color() {
|
|
return this._color;
|
|
},
|
|
set: function color(value) {
|
|
this._color = value;
|
|
}
|
|
},
|
|
display: {
|
|
get: function display() {
|
|
return this._display;
|
|
},
|
|
set: function display(value) {
|
|
this._display = value;
|
|
}
|
|
},
|
|
font: {
|
|
get: function font() {
|
|
return this._font;
|
|
},
|
|
set: function font(value) {
|
|
this._font = value;
|
|
}
|
|
},
|
|
indent: {
|
|
get: function indent() {
|
|
return this._indent;
|
|
},
|
|
set: function indent(value) {
|
|
this._indent = value;
|
|
}
|
|
},
|
|
italic: {
|
|
get: function italic() {
|
|
return this._italic;
|
|
},
|
|
set: function italic(value) {
|
|
this._italic = value;
|
|
}
|
|
},
|
|
kerning: {
|
|
get: function kerning() {
|
|
return this._kerning;
|
|
},
|
|
set: function kerning(value) {
|
|
this._kerning = value;
|
|
}
|
|
},
|
|
leading: {
|
|
get: function leading() {
|
|
return this._leading;
|
|
},
|
|
set: function leading(value) {
|
|
this._leading = value;
|
|
}
|
|
},
|
|
leftMargin: {
|
|
get: function leftMargin() {
|
|
return this._leftMargin;
|
|
},
|
|
set: function leftMargin(value) {
|
|
this._leftMargin = value;
|
|
}
|
|
},
|
|
letterSpacing: {
|
|
get: function letterSpacing() {
|
|
return this._letterSpacing;
|
|
},
|
|
set: function letterSpacing(value) {
|
|
this._letterSpacing = value;
|
|
}
|
|
},
|
|
rightMargin: {
|
|
get: function rightMargin() {
|
|
return this._rightMargin;
|
|
},
|
|
set: function rightMargin(value) {
|
|
this._rightMargin = value;
|
|
}
|
|
},
|
|
size: {
|
|
get: function size() {
|
|
return this._size;
|
|
},
|
|
set: function size(value) {
|
|
this._size = value;
|
|
}
|
|
},
|
|
tabStops: {
|
|
get: function tabStops() {
|
|
return this._tabStops;
|
|
},
|
|
set: function tabStops(value) {
|
|
this._tabStops = value;
|
|
}
|
|
},
|
|
target: {
|
|
get: function target() {
|
|
return this._target;
|
|
},
|
|
set: function target(value) {
|
|
this._target = value;
|
|
}
|
|
},
|
|
underline: {
|
|
get: function underline() {
|
|
return this._underline;
|
|
},
|
|
set: function underline(value) {
|
|
this._underline = value;
|
|
}
|
|
},
|
|
url: {
|
|
get: function url() {
|
|
return this._url;
|
|
},
|
|
set: function url(value) {
|
|
this._url = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var ContentElementDefinition = function () {
|
|
return {
|
|
__class__: 'flash.text.engine.ContentElement',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
textBlock: {
|
|
get: function textBlock() {
|
|
notImplemented('ContentElement.textBlock');
|
|
return this._textBlock;
|
|
}
|
|
},
|
|
textBlockBeginIndex: {
|
|
get: function textBlockBeginIndex() {
|
|
notImplemented('ContentElement.textBlockBeginIndex');
|
|
return this._textBlockBeginIndex;
|
|
}
|
|
},
|
|
elementFormat: {
|
|
get: function elementFormat() {
|
|
return this._elementFormat;
|
|
},
|
|
set: function elementFormat(value) {
|
|
somewhatImplemented('ContentElement.elementFormat');
|
|
this._elementFormat = value;
|
|
}
|
|
},
|
|
eventMirror: {
|
|
get: function eventMirror() {
|
|
return this._eventMirror;
|
|
},
|
|
set: function eventMirror(value) {
|
|
somewhatImplemented('ContentElement.eventMirror');
|
|
this._eventMirror = value;
|
|
}
|
|
},
|
|
groupElement: {
|
|
get: function groupElement() {
|
|
notImplemented('ContentElement.groupElement');
|
|
return this._groupElement;
|
|
}
|
|
},
|
|
rawText: {
|
|
get: function rawText() {
|
|
notImplemented('ContentElement.rawText');
|
|
return this._rawText;
|
|
}
|
|
},
|
|
text: {
|
|
get: function text() {
|
|
notImplemented('ContentElement.text');
|
|
return this._text;
|
|
}
|
|
},
|
|
textRotation: {
|
|
get: function textRotation() {
|
|
return this._textRotation;
|
|
},
|
|
set: function textRotation(value) {
|
|
somewhatImplemented('ContentElement.textRotation');
|
|
this._textRotation = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var ElementFormatDefinition = function () {
|
|
return {
|
|
__class__: 'flash.text.engine.ElementFormat',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
getFontMetrics: function getFontMetrics() {
|
|
notImplemented('ElementFormat.getFontMetrics');
|
|
},
|
|
alignmentBaseline: {
|
|
get: function alignmentBaseline() {
|
|
return this._alignmentBaseline;
|
|
},
|
|
set: function alignmentBaseline(alignmentBaseline) {
|
|
somewhatImplemented('ElementFormat.alignmentBaseline');
|
|
this._alignmentBaseline = alignmentBaseline;
|
|
}
|
|
},
|
|
alpha: {
|
|
get: function alpha() {
|
|
return this._alpha;
|
|
},
|
|
set: function alpha(value) {
|
|
somewhatImplemented('ElementFormat.alpha');
|
|
this._alpha = value;
|
|
}
|
|
},
|
|
baselineShift: {
|
|
get: function baselineShift() {
|
|
return this._baselineShift;
|
|
},
|
|
set: function baselineShift(value) {
|
|
somewhatImplemented('ElementFormat.baselineShift');
|
|
this._baselineShift = value;
|
|
}
|
|
},
|
|
breakOpportunity: {
|
|
get: function breakOpportunity() {
|
|
return this._breakOpportunity;
|
|
},
|
|
set: function breakOpportunity(opportunityType) {
|
|
somewhatImplemented('ElementFormat.breakOpportunity');
|
|
this._breakOpportunity = opportunityType;
|
|
}
|
|
},
|
|
color: {
|
|
get: function color() {
|
|
return this._color;
|
|
},
|
|
set: function color(value) {
|
|
somewhatImplemented('ElementFormat.color');
|
|
this._color = value;
|
|
}
|
|
},
|
|
dominantBaseline: {
|
|
get: function dominantBaseline() {
|
|
return this._dominantBaseline;
|
|
},
|
|
set: function dominantBaseline(dominantBaseline) {
|
|
somewhatImplemented('ElementFormat.dominantBaseline');
|
|
this._dominantBaseline = dominantBaseline;
|
|
}
|
|
},
|
|
fontDescription: {
|
|
get: function fontDescription() {
|
|
return this._fontDescription;
|
|
},
|
|
set: function fontDescription(value) {
|
|
somewhatImplemented('ElementFormat.fontDescription');
|
|
this._fontDescription = value;
|
|
}
|
|
},
|
|
digitCase: {
|
|
get: function digitCase() {
|
|
return this._digitCase;
|
|
},
|
|
set: function digitCase(digitCaseType) {
|
|
somewhatImplemented('ElementFormat.digitCase');
|
|
this._digitCase = digitCaseType;
|
|
}
|
|
},
|
|
digitWidth: {
|
|
get: function digitWidth() {
|
|
return this._digitWidth;
|
|
},
|
|
set: function digitWidth(digitWidthType) {
|
|
somewhatImplemented('ElementFormat.digitWidth');
|
|
this._digitWidth = digitWidthType;
|
|
}
|
|
},
|
|
ligatureLevel: {
|
|
get: function ligatureLevel() {
|
|
return this._ligatureLevel;
|
|
},
|
|
set: function ligatureLevel(ligatureLevelType) {
|
|
somewhatImplemented('ElementFormat.ligatureLevel');
|
|
this._ligatureLevel = ligatureLevelType;
|
|
}
|
|
},
|
|
fontSize: {
|
|
get: function fontSize() {
|
|
return this._fontSize;
|
|
},
|
|
set: function fontSize(value) {
|
|
somewhatImplemented('ElementFormat.fontSize');
|
|
this._fontSize = value;
|
|
}
|
|
},
|
|
kerning: {
|
|
get: function kerning() {
|
|
return this._kerning;
|
|
},
|
|
set: function kerning(value) {
|
|
somewhatImplemented('ElementFormat.kerning');
|
|
this._kerning = value;
|
|
}
|
|
},
|
|
locale: {
|
|
get: function locale() {
|
|
return this._locale;
|
|
},
|
|
set: function locale(value) {
|
|
somewhatImplemented('ElementFormat.locale');
|
|
this._locale = value;
|
|
}
|
|
},
|
|
textRotation: {
|
|
get: function textRotation() {
|
|
return this._textRotation;
|
|
},
|
|
set: function textRotation(value) {
|
|
somewhatImplemented('ElementFormat.textRotation');
|
|
this._textRotation = value;
|
|
}
|
|
},
|
|
trackingRight: {
|
|
get: function trackingRight() {
|
|
return this._trackingRight;
|
|
},
|
|
set: function trackingRight(value) {
|
|
somewhatImplemented('ElementFormat.trackingRight');
|
|
this._trackingRight = value;
|
|
}
|
|
},
|
|
trackingLeft: {
|
|
get: function trackingLeft() {
|
|
return this._trackingLeft;
|
|
},
|
|
set: function trackingLeft(value) {
|
|
somewhatImplemented('ElementFormat.trackingLeft');
|
|
this._trackingLeft = value;
|
|
}
|
|
},
|
|
typographicCase: {
|
|
get: function typographicCase() {
|
|
return this._typographicCase;
|
|
},
|
|
set: function typographicCase(typographicCaseType) {
|
|
somewhatImplemented('ElementFormat.typographicCase');
|
|
this._typographicCase = typographicCaseType;
|
|
}
|
|
},
|
|
locked: {
|
|
get: function locked() {
|
|
notImplemented('ElementFormat.locked');
|
|
return this._locked;
|
|
},
|
|
set: function locked(value) {
|
|
notImplemented('ElementFormat.locked');
|
|
this._locked = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var FontDescriptionDefinition = function () {
|
|
return {
|
|
__class__: 'flash.text.engine.FontDescription',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
isFontCompatible: function isFontCompatible(fontName, fontWeight, fontPosture) {
|
|
notImplemented('FontDescription.isFontCompatible');
|
|
},
|
|
isDeviceFontCompatible: function isDeviceFontCompatible(fontName, fontWeight, fontPosture) {
|
|
notImplemented('FontDescription.isDeviceFontCompatible');
|
|
}
|
|
},
|
|
instance: {
|
|
renderingMode: {
|
|
get: function renderingMode() {
|
|
return this._renderingMode;
|
|
},
|
|
set: function renderingMode(value) {
|
|
somewhatImplemented('FontDescription.renderingMode');
|
|
this._renderingMode = value;
|
|
}
|
|
},
|
|
fontLookup: {
|
|
get: function fontLookup() {
|
|
return this._fontLookup;
|
|
},
|
|
set: function fontLookup(value) {
|
|
somewhatImplemented('FontDescription.fontLookup');
|
|
this._fontLookup = value;
|
|
}
|
|
},
|
|
fontName: {
|
|
get: function fontName() {
|
|
return this._fontName;
|
|
},
|
|
set: function fontName(value) {
|
|
somewhatImplemented('FontDescription.fontName');
|
|
this._fontName = value;
|
|
}
|
|
},
|
|
fontPosture: {
|
|
get: function fontPosture() {
|
|
return this._fontPosture;
|
|
},
|
|
set: function fontPosture(value) {
|
|
somewhatImplemented('FontDescription.fontPosture');
|
|
this._fontPosture = value;
|
|
}
|
|
},
|
|
fontWeight: {
|
|
get: function fontWeight() {
|
|
return this._fontWeight;
|
|
},
|
|
set: function fontWeight(value) {
|
|
somewhatImplemented('FontDescription.fontWeight');
|
|
this._fontWeight = value;
|
|
}
|
|
},
|
|
cffHinting: {
|
|
get: function cffHinting() {
|
|
return this._cffHinting;
|
|
},
|
|
set: function cffHinting(value) {
|
|
somewhatImplemented('FontDescription.cffHinting');
|
|
this._cffHinting = value;
|
|
}
|
|
},
|
|
locked: {
|
|
get: function locked() {
|
|
notImplemented('FontDescription.locked');
|
|
return this._locked;
|
|
},
|
|
set: function locked(value) {
|
|
notImplemented('FontDescription.locked');
|
|
this._locked = value;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
static: {},
|
|
instance: {}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var GroupElementDefinition = function () {
|
|
return {
|
|
__class__: 'flash.text.engine.GroupElement',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
getElementAt: function getElementAt(index) {
|
|
notImplemented('GroupElement.getElementAt');
|
|
},
|
|
setElements: function setElements(value) {
|
|
somewhatImplemented('GroupElement.setElements');
|
|
this._elements = value;
|
|
},
|
|
groupElements: function groupElements(beginIndex, endIndex) {
|
|
notImplemented('GroupElement.groupElements');
|
|
},
|
|
ungroupElements: function ungroupElements(groupIndex) {
|
|
notImplemented('GroupElement.ungroupElements');
|
|
},
|
|
mergeTextElements: function mergeTextElements(beginIndex, endIndex) {
|
|
notImplemented('GroupElement.mergeTextElements');
|
|
},
|
|
splitTextElement: function splitTextElement(elementIndex, splitIndex) {
|
|
notImplemented('GroupElement.splitTextElement');
|
|
},
|
|
replaceElements: function replaceElements(beginIndex, endIndex, newElements) {
|
|
notImplemented('GroupElement.replaceElements');
|
|
},
|
|
getElementAtCharIndex: function getElementAtCharIndex(charIndex) {
|
|
notImplemented('GroupElement.getElementAtCharIndex');
|
|
},
|
|
elementCount: {
|
|
get: function elementCount() {
|
|
notImplemented('GroupElement.elementCount');
|
|
return this._elementCount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var SpaceJustifierDefinition = function () {
|
|
return {
|
|
__class__: 'flash.text.engine.SpaceJustifier',
|
|
initialize: function () {
|
|
this._letterSpacing = false;
|
|
this._optimumSpacing = 1;
|
|
this._minimumSpacing = 0.5;
|
|
this._maximumSpacing = 1.5;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
cloneSpacing: function cloneSpacing(justifier) {
|
|
somewhatImplemented('SpaceJustifier.cloneSpacing');
|
|
justifier._optimumSpacing = this._optimumSpacing;
|
|
justifier._minimumSpacing = this._minimumSpacing;
|
|
justifier._maximumSpacing = this._maximumSpacing;
|
|
},
|
|
letterSpacing: {
|
|
get: function letterSpacing() {
|
|
return this._letterSpacing;
|
|
},
|
|
set: function letterSpacing(value) {
|
|
somewhatImplemented('SpaceJustifier.letterSpacing');
|
|
this._letterSpacing = value;
|
|
}
|
|
},
|
|
minimumSpacing: {
|
|
get: function minimumSpacing() {
|
|
return this._minimumSpacing;
|
|
},
|
|
set: function minimumSpacing(value) {
|
|
somewhatImplemented('SpaceJustifier.minimumSpacing');
|
|
this._minimumSpacing = value;
|
|
}
|
|
},
|
|
optimumSpacing: {
|
|
get: function optimumSpacing() {
|
|
return this._optimumSpacing;
|
|
},
|
|
set: function optimumSpacing(value) {
|
|
somewhatImplemented('SpaceJustifier.optimumSpacing');
|
|
this._optimumSpacing = value;
|
|
}
|
|
},
|
|
maximumSpacing: {
|
|
get: function maximumSpacing() {
|
|
return this._maximumSpacing;
|
|
},
|
|
set: function maximumSpacing(value) {
|
|
somewhatImplemented('SpaceJustifier.maximumSpacing');
|
|
this._maximumSpacing = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var TextBlockDefinition = function () {
|
|
return {
|
|
__class__: 'flash.text.engine.TextBlock',
|
|
initialize: function () {
|
|
this._firstLine = null;
|
|
this._lastLine = null;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
getTextJustifier: function getTextJustifier() {
|
|
return this._textJustifier;
|
|
},
|
|
setTextJustifier: function setTextJustifier(value) {
|
|
somewhatImplemented('TextBlock.setTextJustifier');
|
|
this._textJustifier = value;
|
|
},
|
|
getTabStops: function getTabStops() {
|
|
return this._tabStops;
|
|
},
|
|
setTabStops: function setTabStops(value) {
|
|
somewhatImplemented('TextBlock.setTabStops');
|
|
this._tabStops = value;
|
|
},
|
|
findNextAtomBoundary: function findNextAtomBoundary(afterCharIndex) {
|
|
notImplemented('TextBlock.findNextAtomBoundary');
|
|
},
|
|
findPreviousAtomBoundary: function findPreviousAtomBoundary(beforeCharIndex) {
|
|
notImplemented('TextBlock.findPreviousAtomBoundary');
|
|
},
|
|
findNextWordBoundary: function findNextWordBoundary(afterCharIndex) {
|
|
notImplemented('TextBlock.findNextWordBoundary');
|
|
},
|
|
findPreviousWordBoundary: function findPreviousWordBoundary(beforeCharIndex) {
|
|
notImplemented('TextBlock.findPreviousWordBoundary');
|
|
},
|
|
getTextLineAtCharIndex: function getTextLineAtCharIndex(charIndex) {
|
|
notImplemented('TextBlock.getTextLineAtCharIndex');
|
|
},
|
|
DoCreateTextLine: function DoCreateTextLine(previousLine, width, lineOffset, fitSomething, reuseLine) {
|
|
somewhatImplemented('TextBlock.DoCreateTextLine');
|
|
if (previousLine) {
|
|
return null;
|
|
}
|
|
var textLine = new flash.text.engine.TextLine();
|
|
textLine._textBlock = this;
|
|
textLine._specifiedWidth = width;
|
|
textLine._rawTextLength = 0;
|
|
textLine._textWidth = 0;
|
|
textLine._textHeight = 0;
|
|
textLine._ascent = 0;
|
|
textLine._descent = 0;
|
|
textLine._unjustifiedTextWidth = 0;
|
|
textLine._validity = 'valid';
|
|
textLine._previousLine = null;
|
|
textLine._nextLine = null;
|
|
this._firstLine = textLine;
|
|
this._lastLine = textLine;
|
|
return textLine;
|
|
},
|
|
releaseLineCreationData: function releaseLineCreationData() {
|
|
notImplemented('TextBlock.releaseLineCreationData');
|
|
},
|
|
releaseLines: function releaseLines(firstLine, lastLine) {
|
|
notImplemented('TextBlock.releaseLines');
|
|
},
|
|
dump: function dump() {
|
|
notImplemented('TextBlock.dump');
|
|
},
|
|
applyNonLinearFontScaling: {
|
|
get: function applyNonLinearFontScaling() {
|
|
return this._applyNonLinearFontScaling;
|
|
},
|
|
set: function applyNonLinearFontScaling(value) {
|
|
somewhatImplemented('TextBlock.applyNonLinearFontScaling');
|
|
this._applyNonLinearFontScaling = value;
|
|
}
|
|
},
|
|
baselineFontDescription: {
|
|
get: function baselineFontDescription() {
|
|
return this._baselineFontDescription;
|
|
},
|
|
set: function baselineFontDescription(value) {
|
|
somewhatImplemented('TextBlock.baselineFontDescription');
|
|
this._baselineFontDescription = value;
|
|
}
|
|
},
|
|
baselineFontSize: {
|
|
get: function baselineFontSize() {
|
|
return this._baselineFontSize;
|
|
},
|
|
set: function baselineFontSize(value) {
|
|
somewhatImplemented('TextBlock.baselineFontSize');
|
|
this._baselineFontSize = value;
|
|
}
|
|
},
|
|
baselineZero: {
|
|
get: function baselineZero() {
|
|
return this._baselineZero;
|
|
},
|
|
set: function baselineZero(value) {
|
|
somewhatImplemented('TextBlock.baselineZero');
|
|
this._baselineZero = value;
|
|
}
|
|
},
|
|
content: {
|
|
get: function content() {
|
|
return this._content;
|
|
},
|
|
set: function content(value) {
|
|
somewhatImplemented('TextBlock.content');
|
|
this._content = value;
|
|
}
|
|
},
|
|
bidiLevel: {
|
|
get: function bidiLevel() {
|
|
return this._bidiLevel;
|
|
},
|
|
set: function bidiLevel(value) {
|
|
somewhatImplemented('TextBlock.bidiLevel');
|
|
this._bidiLevel = value;
|
|
}
|
|
},
|
|
firstInvalidLine: {
|
|
get: function firstInvalidLine() {
|
|
notImplemented('TextBlock.firstInvalidLine');
|
|
return this._firstInvalidLine;
|
|
}
|
|
},
|
|
firstLine: {
|
|
get: function firstLine() {
|
|
somewhatImplemented('TextBlock.firstLine');
|
|
return this._firstLine;
|
|
}
|
|
},
|
|
lastLine: {
|
|
get: function lastLine() {
|
|
somewhatImplemented('TextBlock.lastLine');
|
|
return this._lastLine;
|
|
}
|
|
},
|
|
textLineCreationResult: {
|
|
get: function textLineCreationResult() {
|
|
notImplemented('TextBlock.textLineCreationResult');
|
|
return this._textLineCreationResult;
|
|
}
|
|
},
|
|
lineRotation: {
|
|
get: function lineRotation() {
|
|
return this._lineRotation;
|
|
},
|
|
set: function lineRotation(value) {
|
|
somewhatImplemented('TextBlock.lineRotation');
|
|
this._lineRotation = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var TextElementDefinition = function () {
|
|
return {
|
|
__class__: 'flash.text.engine.TextElement',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
replaceText: function replaceText(beginIndex, endIndex, newText) {
|
|
somewhatImplemented('TextElement.replaceText');
|
|
var text = this._text || '';
|
|
this._text = text.slice(0, beginIndex) + newText + text.slice(endIndex);
|
|
},
|
|
text: {
|
|
set: function text(value) {
|
|
somewhatImplemented('TextElement.text');
|
|
this._text = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var TextJustifierDefinition = function () {
|
|
return {
|
|
__class__: 'flash.text.engine.TextJustifier',
|
|
initialize: function () {
|
|
this._locale = null;
|
|
this._lineJustification = null;
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
setLocale: function setLocale(value) {
|
|
somewhatImplemented('TextJustifier.setLocale');
|
|
this._locale = value;
|
|
},
|
|
locale: {
|
|
get: function locale() {
|
|
return this._locale;
|
|
}
|
|
},
|
|
lineJustification: {
|
|
get: function lineJustification() {
|
|
return this._lineJustification;
|
|
},
|
|
set: function lineJustification(value) {
|
|
somewhatImplemented('TextJustifier.lineJustification');
|
|
this._lineJustification = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var TextLineDefinition = function () {
|
|
return {
|
|
__class__: 'flash.text.engine.TextLine',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
getAtomIndexAtPoint: function getAtomIndexAtPoint(stageX, stageY) {
|
|
notImplemented('TextLine.getAtomIndexAtPoint');
|
|
},
|
|
getAtomIndexAtCharIndex: function getAtomIndexAtCharIndex(charIndex) {
|
|
notImplemented('TextLine.getAtomIndexAtCharIndex');
|
|
},
|
|
getAtomBounds: function getAtomBounds(atomIndex) {
|
|
notImplemented('TextLine.getAtomBounds');
|
|
},
|
|
getAtomBidiLevel: function getAtomBidiLevel(atomIndex) {
|
|
notImplemented('TextLine.getAtomBidiLevel');
|
|
},
|
|
getAtomTextRotation: function getAtomTextRotation(atomIndex) {
|
|
notImplemented('TextLine.getAtomTextRotation');
|
|
},
|
|
getAtomTextBlockBeginIndex: function getAtomTextBlockBeginIndex(atomIndex) {
|
|
notImplemented('TextLine.getAtomTextBlockBeginIndex');
|
|
},
|
|
getAtomTextBlockEndIndex: function getAtomTextBlockEndIndex(atomIndex) {
|
|
notImplemented('TextLine.getAtomTextBlockEndIndex');
|
|
},
|
|
getAtomCenter: function getAtomCenter(atomIndex) {
|
|
notImplemented('TextLine.getAtomCenter');
|
|
},
|
|
getAtomWordBoundaryOnLeft: function getAtomWordBoundaryOnLeft(atomIndex) {
|
|
notImplemented('TextLine.getAtomWordBoundaryOnLeft');
|
|
},
|
|
getAtomGraphic: function getAtomGraphic(atomIndex) {
|
|
notImplemented('TextLine.getAtomGraphic');
|
|
},
|
|
getBaselinePosition: function getBaselinePosition(baseline) {
|
|
notImplemented('TextLine.getBaselinePosition');
|
|
},
|
|
dump: function dump() {
|
|
notImplemented('TextLine.dump');
|
|
},
|
|
textBlock: {
|
|
get: function textBlock() {
|
|
notImplemented('TextLine.textBlock');
|
|
return this._textBlock;
|
|
}
|
|
},
|
|
hasGraphicElement: {
|
|
get: function hasGraphicElement() {
|
|
notImplemented('TextLine.hasGraphicElement');
|
|
return this._hasGraphicElement;
|
|
}
|
|
},
|
|
hasTabs: {
|
|
get: function hasTabs() {
|
|
notImplemented('TextLine.hasTabs');
|
|
return this._hasTabs;
|
|
}
|
|
},
|
|
nextLine: {
|
|
get: function nextLine() {
|
|
somewhatImplemented('TextLine.nextLine');
|
|
return this._nextLine;
|
|
}
|
|
},
|
|
previousLine: {
|
|
get: function previousLine() {
|
|
somewhatImplemented('TextLine.previousLine');
|
|
return this._previousLine;
|
|
}
|
|
},
|
|
ascent: {
|
|
get: function ascent() {
|
|
somewhatImplemented('TextLine.ascent');
|
|
return this._ascent;
|
|
}
|
|
},
|
|
descent: {
|
|
get: function descent() {
|
|
somewhatImplemented('TextLine.descent');
|
|
return this._descent;
|
|
}
|
|
},
|
|
textHeight: {
|
|
get: function textHeight() {
|
|
somewhatImplemented('TextLine.textHeight');
|
|
return this._textHeight;
|
|
}
|
|
},
|
|
textWidth: {
|
|
get: function textWidth() {
|
|
somewhatImplemented('TextLine.textWidth');
|
|
return this._textWidth;
|
|
}
|
|
},
|
|
totalAscent: {
|
|
get: function totalAscent() {
|
|
notImplemented('TextLine.totalAscent');
|
|
return this._totalAscent;
|
|
}
|
|
},
|
|
totalDescent: {
|
|
get: function totalDescent() {
|
|
notImplemented('TextLine.totalDescent');
|
|
return this._totalDescent;
|
|
}
|
|
},
|
|
totalHeight: {
|
|
get: function totalHeight() {
|
|
notImplemented('TextLine.totalHeight');
|
|
return this._totalHeight;
|
|
}
|
|
},
|
|
textBlockBeginIndex: {
|
|
get: function textBlockBeginIndex() {
|
|
notImplemented('TextLine.textBlockBeginIndex');
|
|
return this._textBlockBeginIndex;
|
|
}
|
|
},
|
|
rawTextLength: {
|
|
get: function rawTextLength() {
|
|
somewhatImplemented('TextLine.rawTextLength');
|
|
return this._rawTextLength;
|
|
}
|
|
},
|
|
specifiedWidth: {
|
|
get: function specifiedWidth() {
|
|
somewhatImplemented('TextLine.specifiedWidth');
|
|
return this._specifiedWidth;
|
|
}
|
|
},
|
|
unjustifiedTextWidth: {
|
|
get: function unjustifiedTextWidth() {
|
|
somewhatImplemented('TextLine.unjustifiedTextWidth');
|
|
return this._unjustifiedTextWidth;
|
|
}
|
|
},
|
|
validity: {
|
|
get: function validity() {
|
|
return this._validity;
|
|
},
|
|
set: function validity(value) {
|
|
somewhatImplemented('TextLine.validity');
|
|
this._validity = value;
|
|
}
|
|
},
|
|
atomCount: {
|
|
get: function atomCount() {
|
|
notImplemented('TextLine.atomCount');
|
|
return this._atomCount;
|
|
}
|
|
},
|
|
mirrorRegions: {
|
|
get: function mirrorRegions() {
|
|
notImplemented('TextLine.mirrorRegions');
|
|
return this._mirrorRegions;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
{
|
|
var ContextMenuDefinition = function () {
|
|
return {
|
|
__class__: 'flash.ui.ContextMenu',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
_checkSupported: function _checkSupported() {
|
|
notImplemented('ContextMenu._checkSupported');
|
|
}
|
|
},
|
|
instance: {
|
|
cloneLinkAndClipboardProperties: function cloneLinkAndClipboardProperties(c) {
|
|
notImplemented('ContextMenu.cloneLinkAndClipboardProperties');
|
|
},
|
|
builtInItems: {
|
|
get: function builtInItems() {
|
|
somewhatImplemented('ContextMenu.builtInItems');
|
|
return this._builtInItems;
|
|
},
|
|
set: function builtInItems(value) {
|
|
somewhatImplemented('ContextMenu.builtInItems');
|
|
this._builtInItems = value;
|
|
}
|
|
},
|
|
customItems: {
|
|
get: function customItems() {
|
|
somewhatImplemented('ContextMenu.customItems');
|
|
return this._customItems;
|
|
},
|
|
set: function customItems(value) {
|
|
somewhatImplemented('ContextMenu.customItems');
|
|
this._customItems = value;
|
|
}
|
|
},
|
|
link: {
|
|
get: function link() {
|
|
notImplemented('ContextMenu.link');
|
|
return this._link;
|
|
},
|
|
set: function link(value) {
|
|
notImplemented('ContextMenu.link');
|
|
this._link = value;
|
|
}
|
|
},
|
|
clipboardMenu: {
|
|
get: function clipboardMenu() {
|
|
notImplemented('ContextMenu.clipboardMenu');
|
|
return this._clipboardMenu;
|
|
},
|
|
set: function clipboardMenu(value) {
|
|
notImplemented('ContextMenu.clipboardMenu');
|
|
this._clipboardMenu = value;
|
|
}
|
|
},
|
|
clipboardItems: {
|
|
get: function clipboardItems() {
|
|
notImplemented('ContextMenu.clipboardItems');
|
|
return this._clipboardItems;
|
|
},
|
|
set: function clipboardItems(value) {
|
|
notImplemented('ContextMenu.clipboardItems');
|
|
this._clipboardItems = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
}
|
|
var ContextMenuItemDefinition = function () {
|
|
return {
|
|
__class__: 'flash.ui.ContextMenuItem',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
caption: {
|
|
get: function caption() {
|
|
somewhatImplemented('ContextMenuItem.caption');
|
|
return this._caption;
|
|
},
|
|
set: function caption(value) {
|
|
somewhatImplemented('ContextMenuItem.caption');
|
|
this._caption = value;
|
|
}
|
|
},
|
|
separatorBefore: {
|
|
get: function separatorBefore() {
|
|
somewhatImplemented('ContextMenuItem.separatorBefore');
|
|
return this._separatorBefore;
|
|
},
|
|
set: function separatorBefore(value) {
|
|
somewhatImplemented('ContextMenuItem.separatorBefore');
|
|
this._separatorBefore = value;
|
|
}
|
|
},
|
|
visible: {
|
|
get: function visible() {
|
|
somewhatImplemented('ContextMenuItem.visible');
|
|
return this._visible;
|
|
},
|
|
set: function visible(value) {
|
|
somewhatImplemented('ContextMenuItem.visible');
|
|
this._visible = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
var ShumwayKeyboardListener = {
|
|
_lastKeyCode: 0,
|
|
_captureKeyPress: false,
|
|
_charCodeMap: [],
|
|
focus: null,
|
|
handleEvent: function (domEvt) {
|
|
var keyCode = domEvt.keyCode;
|
|
if (domEvt.type === 'keydown') {
|
|
this._lastKeyCode = keyCode;
|
|
this._captureKeyPress = keyCode === 8 || keyCode === 9 || keyCode === 13 || keyCode === 32 || keyCode >= 48 && keyCode <= 90 || keyCode > 145;
|
|
if (this._captureKeyPress) {
|
|
return;
|
|
}
|
|
this._charCodeMap[keyCode] = 0;
|
|
} else if (domEvt.type === 'keypress') {
|
|
if (this._captureKeyPress) {
|
|
keyCode = this._lastKeyCode;
|
|
this._charCodeMap[keyCode] = domEvt.charCode;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
if (this.focus) {
|
|
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));
|
|
}
|
|
}
|
|
};
|
|
window.addEventListener('keydown', ShumwayKeyboardListener);
|
|
window.addEventListener('keypress', ShumwayKeyboardListener);
|
|
window.addEventListener('keyup', ShumwayKeyboardListener);
|
|
var KeyboardDefinition = function () {
|
|
var def = {
|
|
get capsLock() {
|
|
return false;
|
|
},
|
|
get hasVirtualKeyboard() {
|
|
return false;
|
|
},
|
|
get numLock() {
|
|
return false;
|
|
},
|
|
get physicalKeyboardType() {
|
|
return 'alphanumeric';
|
|
},
|
|
get isAccessible() {
|
|
return true;
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
script: {
|
|
static: scriptProperties('public', [
|
|
'A',
|
|
'ALTERNATE',
|
|
'AUDIO',
|
|
'B',
|
|
'BACK',
|
|
'BACKQUOTE',
|
|
'BACKSLASH',
|
|
'BACKSPACE',
|
|
'BLUE',
|
|
'C',
|
|
'CAPS_LOCK',
|
|
'CHANNEL_DOWN',
|
|
'CHANNEL_UP',
|
|
'COMMA',
|
|
'COMMAND',
|
|
'CONTROL',
|
|
'D',
|
|
'DELETE',
|
|
'DOWN',
|
|
'DVR',
|
|
'E',
|
|
'END',
|
|
'ENTER',
|
|
'EQUAL',
|
|
'ESCAPE',
|
|
'EXIT',
|
|
'F',
|
|
'F1',
|
|
'F10',
|
|
'F11',
|
|
'F12',
|
|
'F13',
|
|
'F14',
|
|
'F15',
|
|
'F2',
|
|
'F3',
|
|
'F4',
|
|
'F5',
|
|
'F6',
|
|
'F7',
|
|
'F8',
|
|
'F9',
|
|
'FAST_FORWARD',
|
|
'G',
|
|
'GREEN',
|
|
'GUIDE',
|
|
'H',
|
|
'HELP',
|
|
'HOME',
|
|
'I',
|
|
'INFO',
|
|
'INPUT',
|
|
'INSERT',
|
|
'J',
|
|
'K',
|
|
'KEYNAME_BEGIN',
|
|
'KEYNAME_BREAK',
|
|
'KEYNAME_CLEARDISPLAY',
|
|
'KEYNAME_CLEARLINE',
|
|
'KEYNAME_DELETE',
|
|
'KEYNAME_DELETECHAR',
|
|
'KEYNAME_DELETELINE',
|
|
'KEYNAME_DOWNARROW',
|
|
'KEYNAME_END',
|
|
'KEYNAME_EXECUTE',
|
|
'KEYNAME_F1',
|
|
'KEYNAME_F10',
|
|
'KEYNAME_F11',
|
|
'KEYNAME_F12',
|
|
'KEYNAME_F13',
|
|
'KEYNAME_F14',
|
|
'KEYNAME_F15',
|
|
'KEYNAME_F16',
|
|
'KEYNAME_F17',
|
|
'KEYNAME_F18',
|
|
'KEYNAME_F19',
|
|
'KEYNAME_F2',
|
|
'KEYNAME_F20',
|
|
'KEYNAME_F21',
|
|
'KEYNAME_F22',
|
|
'KEYNAME_F23',
|
|
'KEYNAME_F24',
|
|
'KEYNAME_F25',
|
|
'KEYNAME_F26',
|
|
'KEYNAME_F27',
|
|
'KEYNAME_F28',
|
|
'KEYNAME_F29',
|
|
'KEYNAME_F3',
|
|
'KEYNAME_F30',
|
|
'KEYNAME_F31',
|
|
'KEYNAME_F32',
|
|
'KEYNAME_F33',
|
|
'KEYNAME_F34',
|
|
'KEYNAME_F35',
|
|
'KEYNAME_F4',
|
|
'KEYNAME_F5',
|
|
'KEYNAME_F6',
|
|
'KEYNAME_F7',
|
|
'KEYNAME_F8',
|
|
'KEYNAME_F9',
|
|
'KEYNAME_FIND',
|
|
'KEYNAME_HELP',
|
|
'KEYNAME_HOME',
|
|
'KEYNAME_INSERT',
|
|
'KEYNAME_INSERTCHAR',
|
|
'KEYNAME_INSERTLINE',
|
|
'KEYNAME_LEFTARROW',
|
|
'KEYNAME_MENU',
|
|
'KEYNAME_MODESWITCH',
|
|
'KEYNAME_NEXT',
|
|
'KEYNAME_PAGEDOWN',
|
|
'KEYNAME_PAGEUP',
|
|
'KEYNAME_PAUSE',
|
|
'KEYNAME_PREV',
|
|
'KEYNAME_PRINT',
|
|
'KEYNAME_PRINTSCREEN',
|
|
'KEYNAME_REDO',
|
|
'KEYNAME_RESET',
|
|
'KEYNAME_RIGHTARROW',
|
|
'KEYNAME_SCROLLLOCK',
|
|
'KEYNAME_SELECT',
|
|
'KEYNAME_STOP',
|
|
'KEYNAME_SYSREQ',
|
|
'KEYNAME_SYSTEM',
|
|
'KEYNAME_UNDO',
|
|
'KEYNAME_UPARROW',
|
|
'KEYNAME_USER',
|
|
'L',
|
|
'LAST',
|
|
'LEFT',
|
|
'LEFTBRACKET',
|
|
'LIVE',
|
|
'M',
|
|
'MASTER_SHELL',
|
|
'MENU',
|
|
'MINUS',
|
|
'N',
|
|
'NEXT',
|
|
'NUMBER_0',
|
|
'NUMBER_1',
|
|
'NUMBER_2',
|
|
'NUMBER_3',
|
|
'NUMBER_4',
|
|
'NUMBER_5',
|
|
'NUMBER_6',
|
|
'NUMBER_7',
|
|
'NUMBER_8',
|
|
'NUMBER_9',
|
|
'NUMPAD',
|
|
'NUMPAD_0',
|
|
'NUMPAD_1',
|
|
'NUMPAD_2',
|
|
'NUMPAD_3',
|
|
'NUMPAD_4',
|
|
'NUMPAD_5',
|
|
'NUMPAD_6',
|
|
'NUMPAD_7',
|
|
'NUMPAD_8',
|
|
'NUMPAD_9',
|
|
'NUMPAD_ADD',
|
|
'NUMPAD_DECIMAL',
|
|
'NUMPAD_DIVIDE',
|
|
'NUMPAD_ENTER',
|
|
'NUMPAD_MULTIPLY',
|
|
'NUMPAD_SUBTRACT',
|
|
'O',
|
|
'P',
|
|
'PAGE_DOWN',
|
|
'PAGE_UP',
|
|
'PAUSE',
|
|
'PERIOD',
|
|
'PLAY',
|
|
'PREVIOUS',
|
|
'Q',
|
|
'QUOTE',
|
|
'R',
|
|
'RECORD',
|
|
'RED',
|
|
'REWIND',
|
|
'RIGHT',
|
|
'RIGHTBRACKET',
|
|
'S',
|
|
'SEARCH',
|
|
'SEMICOLON',
|
|
'SETUP',
|
|
'SHIFT',
|
|
'SKIP_BACKWARD',
|
|
'SKIP_FORWARD',
|
|
'SLASH',
|
|
'SPACE',
|
|
'STOP',
|
|
'STRING_BEGIN',
|
|
'STRING_BREAK',
|
|
'STRING_CLEARDISPLAY',
|
|
'STRING_CLEARLINE',
|
|
'STRING_DELETE',
|
|
'STRING_DELETECHAR',
|
|
'STRING_DELETELINE',
|
|
'STRING_DOWNARROW',
|
|
'STRING_END',
|
|
'STRING_EXECUTE',
|
|
'STRING_F1',
|
|
'STRING_F10',
|
|
'STRING_F11',
|
|
'STRING_F12',
|
|
'STRING_F13',
|
|
'STRING_F14',
|
|
'STRING_F15',
|
|
'STRING_F16',
|
|
'STRING_F17',
|
|
'STRING_F18',
|
|
'STRING_F19',
|
|
'STRING_F2',
|
|
'STRING_F20',
|
|
'STRING_F21',
|
|
'STRING_F22',
|
|
'STRING_F23',
|
|
'STRING_F24',
|
|
'STRING_F25',
|
|
'STRING_F26',
|
|
'STRING_F27',
|
|
'STRING_F28',
|
|
'STRING_F29',
|
|
'STRING_F3',
|
|
'STRING_F30',
|
|
'STRING_F31',
|
|
'STRING_F32',
|
|
'STRING_F33',
|
|
'STRING_F34',
|
|
'STRING_F35',
|
|
'STRING_F4',
|
|
'STRING_F5',
|
|
'STRING_F6',
|
|
'STRING_F7',
|
|
'STRING_F8',
|
|
'STRING_F9',
|
|
'STRING_FIND',
|
|
'STRING_HELP',
|
|
'STRING_HOME',
|
|
'STRING_INSERT',
|
|
'STRING_INSERTCHAR',
|
|
'STRING_INSERTLINE',
|
|
'STRING_LEFTARROW',
|
|
'STRING_MENU',
|
|
'STRING_MODESWITCH',
|
|
'STRING_NEXT',
|
|
'STRING_PAGEDOWN',
|
|
'STRING_PAGEUP',
|
|
'STRING_PAUSE',
|
|
'STRING_PREV',
|
|
'STRING_PRINT',
|
|
'STRING_PRINTSCREEN',
|
|
'STRING_REDO',
|
|
'STRING_RESET',
|
|
'STRING_RIGHTARROW',
|
|
'STRING_SCROLLLOCK',
|
|
'STRING_SELECT',
|
|
'STRING_STOP',
|
|
'STRING_SYSREQ',
|
|
'STRING_SYSTEM',
|
|
'STRING_UNDO',
|
|
'STRING_UPARROW',
|
|
'STRING_USER',
|
|
'SUBTITLE',
|
|
'T',
|
|
'TAB',
|
|
'U',
|
|
'UP',
|
|
'V',
|
|
'VOD',
|
|
'W',
|
|
'X',
|
|
'Y',
|
|
'YELLOW',
|
|
'Z',
|
|
'CharCodeStrings'
|
|
])
|
|
},
|
|
native: {
|
|
instance: {
|
|
capsLock: desc(def, 'capsLock'),
|
|
hasVirtualKeyboard: desc(def, 'hasVirtualKeyboard'),
|
|
numLock: desc(def, 'numLock'),
|
|
physicalKeyboardType: desc(def, 'physicalKeyboardType'),
|
|
isAccessible: desc(def, 'isAccessible')
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var MouseDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.ui.Mouse'
|
|
};
|
|
function hide() {
|
|
}
|
|
function show() {
|
|
}
|
|
function registerCursor() {
|
|
notImplemented();
|
|
}
|
|
function unregisterCursor() {
|
|
notImplemented();
|
|
}
|
|
def.__glue__ = {
|
|
native: {
|
|
static: {
|
|
cursor: {
|
|
get: function () {
|
|
return 'auto';
|
|
},
|
|
set: function () {
|
|
notImplemented();
|
|
}
|
|
},
|
|
supportsCursor: {
|
|
get: function () {
|
|
return true;
|
|
}
|
|
},
|
|
supportsNativeCursor: {
|
|
get: function () {
|
|
return true;
|
|
}
|
|
},
|
|
hide: hide,
|
|
show: show,
|
|
registerCursor: registerCursor,
|
|
unregisterCursor: unregisterCursor
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var MouseCursorDataDefinition = function () {
|
|
return {
|
|
__class__: 'flash.ui.MouseCursorData',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
data: {
|
|
get: function data() {
|
|
notImplemented('MouseCursorData.data');
|
|
return this._data;
|
|
},
|
|
set: function data(data) {
|
|
notImplemented('MouseCursorData.data');
|
|
this._data = data;
|
|
}
|
|
},
|
|
hotSpot: {
|
|
get: function hotSpot() {
|
|
notImplemented('MouseCursorData.hotSpot');
|
|
return this._hotSpot;
|
|
},
|
|
set: function hotSpot(data) {
|
|
notImplemented('MouseCursorData.hotSpot');
|
|
this._hotSpot = data;
|
|
}
|
|
},
|
|
frameRate: {
|
|
get: function frameRate() {
|
|
notImplemented('MouseCursorData.frameRate');
|
|
return this._frameRate;
|
|
},
|
|
set: function frameRate(data) {
|
|
notImplemented('MouseCursorData.frameRate');
|
|
this._frameRate = data;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
{
|
|
var DictionaryDefinition = function () {
|
|
return {
|
|
__class__: 'flash.utils.Dictionary',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {},
|
|
instance: {
|
|
init: function init(weakKeys) {
|
|
notImplemented('Dictionary.init');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
}
|
|
var TimerDefinition = function () {
|
|
var def = {
|
|
__class__: 'flash.utils.Timer',
|
|
initialize: function () {
|
|
this._running = false;
|
|
}
|
|
};
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
running: {
|
|
get: function () {
|
|
return this._running;
|
|
}
|
|
},
|
|
_start: function (delay, closure) {
|
|
this._running = true;
|
|
this.interval = setInterval(closure, delay);
|
|
},
|
|
stop: function () {
|
|
this._running = false;
|
|
clearInterval(this.interval);
|
|
},
|
|
_tick: function () {
|
|
if (!this._running) {
|
|
return;
|
|
}
|
|
this._dispatchEvent(new flash.events.TimerEvent('timer', true, false));
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
{
|
|
var AccessibilityDefinition = function () {
|
|
return {
|
|
__class__: 'flash.accessibility.Accessibility',
|
|
initialize: function () {
|
|
},
|
|
__glue__: {
|
|
native: {
|
|
static: {
|
|
sendEvent: function sendEvent(source, childID, eventType, nonHTML) {
|
|
notImplemented('Accessibility.sendEvent');
|
|
},
|
|
updateProperties: function updateProperties() {
|
|
notImplemented('Accessibility.updateProperties');
|
|
},
|
|
active: {
|
|
get: function active() {
|
|
somewhatImplemented('Accessibility.active');
|
|
return false;
|
|
}
|
|
}
|
|
},
|
|
instance: {}
|
|
}
|
|
}
|
|
};
|
|
}.call(this);
|
|
}
|
|
{
|
|
var AS2ButtonDefinition = function () {
|
|
var def = {
|
|
__class__: 'avm1lib.AS2Button',
|
|
initialize: function () {
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
_as3Object: {
|
|
get: function () {
|
|
return this.$nativeObject;
|
|
}
|
|
},
|
|
_init: function init(nativeButton) {
|
|
Object.defineProperty(this, '$nativeObject', {
|
|
value: nativeButton
|
|
});
|
|
nativeButton.$as2Object = this;
|
|
initDefaultListeners(this);
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
}
|
|
var AS2GlobalsDefinition = function () {
|
|
var def = {
|
|
__class__: 'avm1lib.AS2Globals',
|
|
initialize: function () {
|
|
flash.text.TextFormat.prototype.asDefinePublicProperty('getTextExtent', {
|
|
value: TextFormatDefinition.as2GetTextExtent,
|
|
writable: false,
|
|
enumerable: false,
|
|
configurable: false
|
|
});
|
|
}
|
|
};
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
ASSetPropFlags: function ASSetPropFlags(obj, children, flags, allowFalse) {
|
|
},
|
|
_addToPendingScripts: function _addToPendingScripts(subject, fn, args) {
|
|
AS2Context.instance.addToPendingScripts(function () {
|
|
fn.apply(subject, args);
|
|
});
|
|
},
|
|
_setLevel: function _setLevel(level, loader) {
|
|
AS2Context.instance.stage._as2SetLevel(level, loader);
|
|
},
|
|
trace: function (expression) {
|
|
var trace = avm2.applicationDomain.getProperty(Multiname.fromSimpleName('trace'), true, true);
|
|
trace(expression);
|
|
}
|
|
},
|
|
static: {
|
|
_addInternalClasses: function _addInternalClasses(proto) {
|
|
proto.asSetPublicProperty('Object', Stubs.Object);
|
|
proto.asSetPublicProperty('Function', Stubs.Function);
|
|
proto.asSetPublicProperty('Array', Stubs.Array);
|
|
proto.asSetPublicProperty('Number', Stubs.Number);
|
|
proto.asSetPublicProperty('Math', avm2.systemDomain.getClass('Math'));
|
|
proto.asSetPublicProperty('Boolean', Stubs.Boolean);
|
|
proto.asSetPublicProperty('Date', Stubs.Date);
|
|
proto.asSetPublicProperty('RegExp', Stubs.RegExp);
|
|
proto.asSetPublicProperty('String', Stubs.String);
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var AS2MovieClipDefinition = function () {
|
|
var def = {
|
|
__class__: 'avm1lib.AS2MovieClip',
|
|
initialize: function () {
|
|
},
|
|
_insertChildAtDepth: function _insertChildAtDepth(mc, depth) {
|
|
return this.$nativeObject._insertChildAtDepth(mc, depth);
|
|
},
|
|
_duplicate: function _duplicate(name, depth, initObject) {
|
|
return this.$nativeObject._duplicate(name, depth, initObject);
|
|
},
|
|
_constructSymbol: function constructSymbol(symbolId, name) {
|
|
var theClass = AS2Context.instance.classes && AS2Context.instance.classes[symbolId];
|
|
var symbolProps = AS2Context.instance.assets[symbolId];
|
|
var symbolClass = flash.display.MovieClip.class;
|
|
var mc = symbolClass.createAsSymbol(symbolProps);
|
|
mc._avm1SymbolClass = theClass;
|
|
symbolClass.instanceConstructor.call(mc);
|
|
this.$nativeObject.addChild(mc);
|
|
return mc;
|
|
},
|
|
_gotoLabel: function (label) {
|
|
this.$nativeObject.gotoLabel(label);
|
|
},
|
|
_callFrame: function callFrame(frame) {
|
|
this.$nativeObject._callFrame(frame);
|
|
},
|
|
init: function init(nativeMovieClip) {
|
|
if (!nativeMovieClip) {
|
|
return;
|
|
}
|
|
Object.defineProperty(this, '$nativeObject', {
|
|
value: nativeMovieClip
|
|
});
|
|
nativeMovieClip.$as2Object = this;
|
|
initDefaultListeners(this);
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
_as3Object: {
|
|
get: function () {
|
|
return this.$nativeObject;
|
|
}
|
|
},
|
|
_init: def.init,
|
|
_insertChildAtDepth: def._insertChildAtDepth,
|
|
_duplicate: def._duplicate,
|
|
_constructSymbol: def._constructSymbol,
|
|
_callFrame: def._callFrame,
|
|
_gotoLabel: def._gotoLabel
|
|
}
|
|
},
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var AS2MovieClipLoaderDefinition = function () {
|
|
var def = {
|
|
__class__: 'avm1lib.AS2MovieClipLoader',
|
|
initialize: function () {
|
|
},
|
|
get _bytesLoaded() {
|
|
return this.$nativeObject._contentLoaderInfo._bytesLoaded;
|
|
}
|
|
};
|
|
var desc = Object.getOwnPropertyDescriptor;
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
$nativeObject: {
|
|
get: function () {
|
|
return this.$nativeObject;
|
|
}
|
|
},
|
|
_bytesLoaded: desc(def, '_bytesLoaded')
|
|
}
|
|
},
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var AS2TextFieldDefinition = function () {
|
|
var def = {
|
|
__class__: 'avm1lib.AS2TextField',
|
|
initialize: function () {
|
|
this._variable = '';
|
|
}
|
|
};
|
|
def.__glue__ = {
|
|
native: {
|
|
instance: {
|
|
variable: {
|
|
get: function () {
|
|
return this._variable;
|
|
},
|
|
set: function (name) {
|
|
if (name === this._variable) {
|
|
return;
|
|
}
|
|
this._variable = name;
|
|
var instance = this.$nativeObject;
|
|
var hasPath = name.indexOf('.') >= 0 || name.indexOf(':') >= 0;
|
|
var clip;
|
|
if (hasPath) {
|
|
var targetPath = name.split(/[.:\/]/g);
|
|
name = targetPath.pop();
|
|
if (targetPath[0] == '_root' || targetPath[0] === '') {
|
|
clip = instance.root._getAS2Object();
|
|
targetPath.shift();
|
|
if (targetPath[0] === '') {
|
|
targetPath.shift();
|
|
}
|
|
} else {
|
|
clip = instance._parent._getAS2Object();
|
|
}
|
|
while (targetPath.length > 0) {
|
|
var childName = targetPath.shift();
|
|
clip = clip.asGetPublicProperty(childName) || clip[childName];
|
|
if (!clip) {
|
|
throw new Error('Cannot find ' + childName + ' variable');
|
|
}
|
|
}
|
|
} else {
|
|
clip = instance._parent._getAS2Object();
|
|
}
|
|
if (!clip.asHasProperty(undefined, name, 0)) {
|
|
clip.asSetPublicProperty(name, instance.text);
|
|
}
|
|
instance._addEventListener('advanceFrame', function () {
|
|
instance.text = '' + clip.asGetPublicProperty(name);
|
|
});
|
|
}
|
|
},
|
|
_as3Object: {
|
|
get: function () {
|
|
return this.$nativeObject;
|
|
}
|
|
},
|
|
_init: function init(nativeTextField) {
|
|
Object.defineProperty(this, '$nativeObject', {
|
|
value: nativeTextField
|
|
});
|
|
nativeTextField.$as2Object = this;
|
|
initDefaultListeners(this);
|
|
}
|
|
}
|
|
},
|
|
script: {
|
|
instance: Glue.ALL
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
var AS2UtilsDefinition = function () {
|
|
var def = {
|
|
__class__: 'avm1lib.AS2Utils',
|
|
initialize: function () {
|
|
}
|
|
};
|
|
function installObjectMethods() {
|
|
var c = Stubs.Object, p = c.asGetPublicProperty('prototype');
|
|
c.asSetPublicProperty('registerClass', function registerClass(name, theClass) {
|
|
var classes = AS2Context.instance.classes || (AS2Context.instance.classes = {});
|
|
classes[name] = theClass;
|
|
});
|
|
p.asDefinePublicProperty('addProperty', {
|
|
value: function addProperty(name, getter, setter) {
|
|
if (typeof name !== 'string' || name === '') {
|
|
return false;
|
|
}
|
|
if (typeof getter !== 'function') {
|
|
return false;
|
|
}
|
|
if (typeof setter !== 'function' && setter !== null) {
|
|
return false;
|
|
}
|
|
this.asDefinePublicProperty(name, {
|
|
get: getter,
|
|
set: setter || undefined,
|
|
configurable: true,
|
|
enumerable: true
|
|
});
|
|
return true;
|
|
},
|
|
writable: false,
|
|
enumerable: false,
|
|
configurable: false
|
|
});
|
|
}
|
|
def.__glue__ = {
|
|
native: {
|
|
static: {
|
|
getAS2Object: function (nativeObject) {
|
|
return nativeObject && nativeObject._getAS2Object ? nativeObject._getAS2Object() : null;
|
|
},
|
|
addProperty: function (obj, propertyName, getter, setter, enumerable) {
|
|
obj.asDefinePublicProperty(propertyName, {
|
|
get: getter,
|
|
set: setter || undefined,
|
|
enumerable: enumerable,
|
|
configurable: true
|
|
});
|
|
},
|
|
resolveTarget: function (target_mc) {
|
|
return AS2Context.instance.resolveTarget(target_mc);
|
|
},
|
|
resolveLevel: function (level) {
|
|
return AS2Context.instance.resolveLevel(level);
|
|
},
|
|
currentStage: {
|
|
get: function () {
|
|
return AS2Context.instance.stage;
|
|
}
|
|
},
|
|
_installObjectMethods: installObjectMethods
|
|
}
|
|
}
|
|
};
|
|
return def;
|
|
}.call(this);
|
|
function initDefaultListeners(thisArg) {
|
|
var defaultListeners = thisArg.asGetPublicProperty('$defaultListeners');
|
|
if (!defaultListeners) {
|
|
return;
|
|
}
|
|
for (var i = 0; i < defaultListeners.length; i++) {
|
|
var p = defaultListeners[i];
|
|
p.asGetPublicProperty('setter').call(thisArg, p.value);
|
|
}
|
|
}
|
|
function bindNativeClassDefinition(nativeName, definition) {
|
|
natives[nativeName] = function (domain, scope, instanceConstructor, baseClass) {
|
|
var c = new Class(undefined, instanceConstructor, ApplicationDomain.coerceCallable);
|
|
c.extend(baseClass);
|
|
c.linkNatives(definition);
|
|
return c;
|
|
};
|
|
}
|
|
var Stubs = new function () {
|
|
var that = this;
|
|
var definitions = createEmptyObject();
|
|
var DEFAULT_DEFINITION = {
|
|
__glue__: {
|
|
script: {
|
|
instance: Glue.ALL,
|
|
static: Glue.ALL
|
|
}
|
|
}
|
|
};
|
|
this.getClassNames = function () {
|
|
return Object.keys(definitions);
|
|
};
|
|
this.onClassCreated = function (eventType, cls) {
|
|
var classOriginalName = cls.classInfo.instanceInfo.name.getOriginalName();
|
|
if (classOriginalName in definitions) {
|
|
cls.link(definitions[classOriginalName] || DEFAULT_DEFINITION);
|
|
}
|
|
};
|
|
function makeStub(container, classSimpleName, shortName) {
|
|
Object.defineProperty(container, shortName, {
|
|
get: function () {
|
|
var cls = avm2.systemDomain.getClass(classSimpleName);
|
|
true;
|
|
Object.defineProperty(container, shortName, {
|
|
value: cls.instanceConstructor,
|
|
writable: false
|
|
});
|
|
return container[shortName];
|
|
},
|
|
configurable: true
|
|
});
|
|
}
|
|
[
|
|
'Boolean',
|
|
'Date',
|
|
'String',
|
|
'Function',
|
|
'Object',
|
|
'Number',
|
|
'Math',
|
|
'Array',
|
|
'RegExp'
|
|
].forEach(function (classSimpleName) {
|
|
makeStub(that, classSimpleName, classSimpleName);
|
|
});
|
|
[
|
|
'Error',
|
|
'DefinitionError',
|
|
'EvalError',
|
|
'RangeError',
|
|
'ReferenceError',
|
|
'SecurityError',
|
|
'SyntaxError',
|
|
'TypeError',
|
|
'URIError',
|
|
'VerifyError',
|
|
'UninitializedError',
|
|
'ArgumentError'
|
|
].forEach(function (classSimpleName) {
|
|
makeStub(that, classSimpleName, classSimpleName);
|
|
});
|
|
function M(classSimpleName, nativeName, definition) {
|
|
return {
|
|
classSimpleName: classSimpleName,
|
|
nativeName: nativeName,
|
|
definition: definition
|
|
};
|
|
}
|
|
[
|
|
M('flash.display.DisplayObject', 'DisplayObjectClass', DisplayObjectDefinition),
|
|
M('flash.display.InteractiveObject', 'InteractiveObjectClass', InteractiveObjectDefinition),
|
|
M('flash.display.DisplayObjectContainer', 'ContainerClass', DisplayObjectContainerDefinition),
|
|
M('flash.display.Sprite', 'SpriteClass', SpriteDefinition),
|
|
M('flash.display.MovieClip', 'MovieClipClass', MovieClipDefinition),
|
|
M('flash.display.Shape', 'ShapeClass', ShapeDefinition),
|
|
M('flash.display.Bitmap', 'BitmapClass', BitmapDefinition),
|
|
M('flash.display.BitmapData', 'BitmapDataClass', BitmapDataDefinition),
|
|
M('flash.display.Stage', 'StageClass', StageDefinition),
|
|
M('flash.display.Loader', 'LoaderClass', LoaderDefinition),
|
|
M('flash.display.LoaderInfo', 'LoaderInfoClass', LoaderInfoDefinition),
|
|
M('flash.display.Graphics', 'GraphicsClass', GraphicsDefinition),
|
|
M('flash.display.SimpleButton', 'SimpleButtonClass', SimpleButtonDefinition),
|
|
M('flash.display.MorphShape', 'MorphShapeClass', MorphShapeDefinition),
|
|
M('flash.display.NativeMenu', 'MenuClass', NativeMenuDefinition),
|
|
M('flash.display.NativeMenuItem', 'MenuItemClass', NativeMenuItemDefinition),
|
|
M('flash.display.FrameLabel', 'FrameLabelClass', FrameLabelDefinition),
|
|
M('flash.display.Scene'),
|
|
M('flash.display.BlendMode'),
|
|
M('flash.display.Shader', 'ShaderClass', ShaderDefinition),
|
|
M('flash.display.ShaderData', 'ShaderDataClass', ShaderDataDefinition),
|
|
M('flash.filters.BevelFilter', 'BevelFilterClass', BevelFilterDefinition),
|
|
M('flash.filters.BitmapFilter', 'BitmapFilterClass', BitmapFilterDefinition),
|
|
M('flash.filters.BlurFilter', 'BlurFilterClass', BlurFilterDefinition),
|
|
M('flash.filters.ColorMatrixFilter', 'ColorMatrixFilterClass', ColorMatrixFilterDefinition),
|
|
M('flash.filters.ConvolutionFilter', 'ConvolutionFilterClass', ConvolutionFilterDefinition),
|
|
M('flash.filters.DisplacementMapFilter', 'DisplacementMapFilterClass', DisplacementMapFilterDefinition),
|
|
M('flash.filters.DropShadowFilter', 'DropShadowFilterClass', DropShadowFilterDefinition),
|
|
M('flash.filters.GlowFilter', 'GlowFilterClass', GlowFilterDefinition),
|
|
M('flash.filters.GradientBevelFilter', 'GradientBevelFilterClass', GradientBevelFilterDefinition),
|
|
M('flash.filters.GradientGlowFilter', 'GradientGlowFilterClass', GradientGlowFilterDefinition),
|
|
M('flash.filters.ShaderFilter', 'ShaderFilterClass', ShaderFilterDefinition),
|
|
M('flash.geom.Point', 'PointClass', PointDefinition),
|
|
M('flash.geom.Rectangle', 'RectangleClass', RectangleDefinition),
|
|
M('flash.geom.Matrix', 'MatrixClass', MatrixDefinition),
|
|
M('flash.geom.Matrix3D', 'Matrix3DClass', Matrix3DDefinition),
|
|
M('flash.geom.Vector3D', 'Vector3DClass', Vector3DDefinition),
|
|
M('flash.geom.Transform', 'TransformClass', TransformDefinition),
|
|
M('flash.geom.ColorTransform', 'ColorTransformClass', ColorTransformDefinition),
|
|
M('flash.events.EventDispatcher', 'EventDispatcherClass', EventDispatcherDefinition),
|
|
M('flash.events.Event', 'EventClass', EventDefinition),
|
|
M('flash.events.IOErrorEvent'),
|
|
M('flash.events.NetStatusEvent'),
|
|
M('flash.events.KeyboardEvent', 'KeyboardEventClass', KeyboardEventDefinition),
|
|
M('flash.events.MouseEvent', 'MouseEventClass', MouseEventDefinition),
|
|
M('flash.events.TextEvent', 'TextEventClass', TextEventDefinition),
|
|
M('flash.events.TimerEvent', 'TimerEventClass', TimerEventDefinition),
|
|
M('flash.events.ProgressEvent'),
|
|
M('flash.events.NetStatusEvent'),
|
|
M('flash.external.ExternalInterface', 'ExternalInterfaceClass', ExternalInterfaceDefinition),
|
|
M('flash.ui.ContextMenu', 'ContextMenuClass', ContextMenuDefinition),
|
|
M('flash.ui.ContextMenuItem', 'ContextMenuItemClass', ContextMenuItemDefinition),
|
|
M('flash.ui.Keyboard', 'KeyboardClass', KeyboardDefinition),
|
|
M('flash.ui.Mouse', 'MouseClass', MouseDefinition),
|
|
M('flash.ui.MouseCursorData', 'MouseCursorDataClass', MouseCursorDataDefinition),
|
|
M('flash.text.Font', 'FontClass', FontDefinition),
|
|
M('flash.text.TextField', 'TextFieldClass', TextFieldDefinition),
|
|
M('flash.text.StaticText', 'StaticTextClass', StaticTextDefinition),
|
|
M('flash.text.StyleSheet', 'StyleSheetClass', StyleSheetDefinition),
|
|
M('flash.text.TextFormat', 'TextFormatClass', TextFormatDefinition),
|
|
M('flash.text.TextLineMetrics'),
|
|
M('flash.text.engine.ContentElement', 'ContentElementClass', ContentElementDefinition),
|
|
M('flash.text.engine.ElementFormat', 'ElementFormatClass', ElementFormatDefinition),
|
|
M('flash.text.engine.FontDescription', 'FontDescriptionClass', FontDescriptionDefinition),
|
|
M('flash.text.engine.GroupElement', 'GroupElementClass', GroupElementDefinition),
|
|
M('flash.text.engine.SpaceJustifier', 'SpaceJustifierClass', SpaceJustifierDefinition),
|
|
M('flash.text.engine.TextBlock', 'TextBlockClass', TextBlockDefinition),
|
|
M('flash.text.engine.TextElement', 'TextElementClass', TextElementDefinition),
|
|
M('flash.text.engine.TextJustifier', 'TextJustifierClass', TextJustifierDefinition),
|
|
M('flash.text.engine.TextLine', 'TextLineClass', TextLineDefinition),
|
|
M('flash.media.Sound', 'SoundClass', SoundDefinition),
|
|
M('flash.media.SoundChannel', 'SoundChannelClass', SoundChannelDefinition),
|
|
M('flash.media.SoundMixer', 'SoundMixerClass', SoundMixerDefinition),
|
|
M('flash.media.SoundTransform', 'SoundTransformClass', SoundTransformDefinition),
|
|
M('flash.media.Video', 'VideoClass', VideoDefinition),
|
|
M('flash.media.ID3Info', 'ID3InfoClass', ID3InfoDefinition),
|
|
M('flash.media.Microphone', 'MicrophoneClass', MicrophoneDefinition),
|
|
M('flash.net.FileFilter', 'FileFilterClass', FileFilterDefinition),
|
|
M('flash.net.NetConnection', 'NetConnectionClass', NetConnectionDefinition),
|
|
M('flash.net.NetStream', 'NetStreamClass', NetStreamDefinition),
|
|
M('flash.net.Responder', 'ResponderClass', ResponderDefinition),
|
|
M('flash.net.URLRequest', 'URLRequestClass', URLRequestDefinition),
|
|
M('flash.net.URLStream', 'URLStreamClass', URLStreamDefinition),
|
|
M('flash.net.URLLoader', 'URLLoaderClass', URLLoaderDefinition),
|
|
M('flash.net.SharedObject', 'SharedObjectClass', SharedObjectDefinition),
|
|
M('flash.net.ObjectEncoding', 'ObjectEncodingClass', ObjectEncodingDefinition),
|
|
M('flash.net.LocalConnection', 'LocalConnectionClass', LocalConnectionDefinition),
|
|
M('flash.net.Socket', 'SocketClass', SocketDefinition),
|
|
M('flash.net.URLVariables'),
|
|
M('packageInternal flash.system.FSCommand', 'FSCommandClass', FSCommandDefinition),
|
|
M('flash.system.Capabilities', 'CapabilitiesClass', CapabilitiesDefinition),
|
|
M('flash.system.System', 'SystemClass', SystemDefinition),
|
|
M('flash.system.Security', 'SecurityClass', SecurityDefinition),
|
|
M('flash.system.SecurityDomain', 'SecurityDomainClass', SecurityDomainDefinition),
|
|
M('flash.system.ApplicationDomain', 'ApplicationDomainClass', ApplicationDomainDefinition),
|
|
M('flash.accessibility.Accessibility', 'AccessibilityClass', AccessibilityDefinition),
|
|
M('flash.utils.Timer', 'TimerClass', TimerDefinition),
|
|
M('avm1lib.AS2Utils', 'AS2Utils', AS2UtilsDefinition),
|
|
M('avm1lib.AS2Broadcaster'),
|
|
M('avm1lib.AS2Key'),
|
|
M('avm1lib.AS2Mouse'),
|
|
M('avm1lib.AS2MovieClip', 'AS2MovieClip', AS2MovieClipDefinition),
|
|
M('avm1lib.AS2Button', 'AS2Button', AS2ButtonDefinition),
|
|
M('avm1lib.AS2TextField', 'AS2TextField', AS2TextFieldDefinition),
|
|
M('avm1lib.AS2Stage'),
|
|
M('avm1lib.AS2System'),
|
|
M('avm1lib.AS2Color'),
|
|
M('avm1lib.AS2Globals', 'AS2Globals', AS2GlobalsDefinition),
|
|
M('avm1lib.AS2MovieClipLoader', 'AS2MovieClipLoader', AS2MovieClipLoaderDefinition)
|
|
].forEach(function (m) {
|
|
var className = Multiname.fromSimpleName(m.classSimpleName);
|
|
var path = className.getOriginalName().split('.');
|
|
var container = this;
|
|
for (var i = 0, j = path.length - 1; i < j; i++) {
|
|
if (!container[path[i]]) {
|
|
container[path[i]] = {};
|
|
}
|
|
container = container[path[i]];
|
|
}
|
|
makeStub(container, m.classSimpleName, path[path.length - 1]);
|
|
if (m.nativeName) {
|
|
bindNativeClassDefinition(m.nativeName, m.definition);
|
|
}
|
|
definitions[className.getOriginalName()] = m.definition;
|
|
});
|
|
}();
|
|
natives['FlashUtilScript::getAliasName'] = function (domain, scope, instanceConstructor, baseClass) {
|
|
return function getAliasName(value) {
|
|
return value.debugName;
|
|
};
|
|
};
|
|
natives['FlashUtilScript::getDefinitionByName'] = natives.getDefinitionByName;
|
|
natives['FlashUtilScript::getTimer'] = function GetTimerMethod(domain, scope, instanceConstructor, baseClass) {
|
|
var start = Date.now();
|
|
return function getTimer() {
|
|
return Date.now() - start;
|
|
};
|
|
};
|
|
natives['FlashUtilScript::escapeMultiByte'] = function EscapeMultiByteMethod(domain, scope, instanceConstructor, baseClass) {
|
|
return escape;
|
|
};
|
|
natives['FlashUtilScript::unescapeMultiByte'] = function UnescapeMultiByteMethod(domain, scope, instanceConstructor, baseClass) {
|
|
return unescape;
|
|
};
|
|
natives['FlashNetScript::navigateToURL'] = function GetNavigateToURLMethod(domain, scope, instanceConstructor, baseClass) {
|
|
return function navigateToURL(request, window_) {
|
|
if (request === null || request === undefined) {
|
|
throwError('TypeError', Errors.NullPointerError, 'request');
|
|
}
|
|
var RequestClass = avm2.systemDomain.getClass('flash.net.URLRequest');
|
|
if (!RequestClass.isInstanceOf(request)) {
|
|
throwError('TypeError', Errors.CheckTypeFailedError, request, 'flash.net.URLRequest');
|
|
}
|
|
var url = request.url;
|
|
if (/^fscommand:/i.test(url)) {
|
|
var fscommand = avm2.applicationDomain.getProperty(Multiname.fromSimpleName('flash.system.fscommand'), true, true);
|
|
fscommand.call(null, url.substring('fscommand:'.length), window_);
|
|
return;
|
|
}
|
|
var targetWindow = window_ || '_parent';
|
|
window.open(FileLoadingService.resolveUrl(url), targetWindow);
|
|
};
|
|
};
|
|
natives['FlashNetScript::sendToURL'] = function GetSendToURLMethod(domain, scope, instanceConstructor, baseClass) {
|
|
return function sendToURL(request) {
|
|
if (request === null || request === undefined) {
|
|
throwError('TypeError', Errors.NullPointerError, 'request');
|
|
}
|
|
var RequestClass = avm2.systemDomain.getClass('flash.net.URLRequest');
|
|
if (!RequestClass.isInstanceOf(request)) {
|
|
throwError('TypeError', Errors.CheckTypeFailedError, request, 'flash.net.URLRequest');
|
|
}
|
|
var session = FileLoadingService.createSession();
|
|
session.onprogress = function () {
|
|
};
|
|
session.open(request);
|
|
};
|
|
};
|
|
natives['Toplevel::registerClassAlias'] = function GetRegisterClassAliasMethod(domain, scope, instance, baseClass) {
|
|
return function registerClassAlias(aliasName, classObject) {
|
|
if (!aliasName) {
|
|
throwError('TypeError', Errors.NullPointerError, 'aliasName');
|
|
}
|
|
if (!classObject) {
|
|
throwError('TypeError', Errors.NullPointerError, 'classObject');
|
|
}
|
|
AMFUtils.aliasesCache.classes.set(classObject, aliasName);
|
|
AMFUtils.aliasesCache.names[aliasName] = classObject;
|
|
};
|
|
};
|
|
natives['Toplevel::getClassByAlias'] = function GetGetClassByAliasMethod(domain, scope, instance, baseClass) {
|
|
return function getClassByAlias(aliasName) {
|
|
if (!aliasName) {
|
|
throwError('TypeError', Errors.NullPointerError, 'aliasName');
|
|
}
|
|
var classObject = AMFUtils.aliasesCache.names[aliasName];
|
|
if (!classObject) {
|
|
throwError('ReferenceError', Errors.ClassNotFoundError, aliasName);
|
|
}
|
|
return classObject;
|
|
};
|
|
};
|