@awayfl/avm2
Version:
Virtual machine for executing AS3 code
218 lines (217 loc) • 8.07 kB
JavaScript
import { MovieClip, FrameScriptManager, Sprite, DisplayObjectContainer, Timeline } from '@awayjs/scene';
import { IS_AX_CLASS } from './AXClass';
import { Settings } from '../Settings';
var ActiveLoaderContext = /** @class */ (function () {
function ActiveLoaderContext() {
}
return ActiveLoaderContext;
}());
export { ActiveLoaderContext };
var USE_WEAK = ('WeakRef' in self) && Settings.USE_WEAK_REF;
if (USE_WEAK) {
console.debug('[OrphanManager] `WeakRef` used for orphans!');
}
// todo: move OrphanManager elsewhere and add strong type
// maybe eve solve the orphan-issue in otherway alltogether
var OrphanManager = /** @class */ (function () {
function OrphanManager() {
}
OrphanManager.addOrphan = function (orphan) {
if (orphan === void 0) { orphan = null; }
if (!orphan) {
return;
}
if (!orphan.isAsset ||
!(orphan.isAsset(MovieClip) ||
orphan.isAsset(Sprite) ||
orphan.isAsset(DisplayObjectContainer))) {
return;
}
if (orphan.id in this.orphans)
return;
this.orphans[orphan.id] = USE_WEAK ? new self.WeakRef(orphan) : orphan;
this.totalOrphansCount++;
};
OrphanManager.removeOrphan = function (orphan) {
if (!(orphan.id in this.orphans))
return;
this.totalOrphansCount--;
delete this.orphans[orphan.id];
};
OrphanManager.updateOrphans = function () {
var orphan;
for (var key in this.orphans) {
orphan = this.orphans[key];
if (USE_WEAK && orphan) {
orphan = orphan === null || orphan === void 0 ? void 0 : orphan.deref();
}
if (orphan) {
if (!orphan.parent) {
orphan.advanceFrame();
FrameScriptManager.execute_as3_constructors_recursiv(orphan);
}
else {
// delete, orphan has parent
this.totalOrphansCount--;
delete this.orphans[key];
}
}
else {
console.debug('[OrphanManager] Orphan was deleted by GC:', key);
this.totalOrphansCount--;
delete this.orphans[key];
}
}
};
OrphanManager.orphans = Object.create(null);
OrphanManager.totalOrphansCount = 0;
return OrphanManager;
}());
export { OrphanManager };
function initTraitsForObject(object, traits) {
if (!traits)
return;
if (traits.slots) {
for (var i = 0; i < traits.slots.length; i++) {
if (traits.slots[i]) {
object[traits.slots[i].multiname.getMangledName()] = traits.slots[i].value;
}
}
}
if (traits.superTraits)
initTraitsForObject(object, traits.superTraits);
return object;
}
/**
* Generic axConstruct method that lives on the AXClass prototype. This just
* creates an empty object with the right prototype and then calls the
* instance initializer.
*
* TODO: Flatten out the argArray, or create an alternate ax helper to
* make object construction faster.
*/
export function axConstruct(argArray) {
var _a, _b, _c, _d;
var _this = this;
var object = Object.create(_this.tPrototype);
initTraitsForObject(object, _this.tPrototype.traits);
var symbol = null;
var timeline = null;
var classToCheck = _this;
// find the AwayJS-timline that should be used for this MC. might be on superclass...
while (classToCheck && !timeline) {
symbol = classToCheck._symbol;
if (symbol && symbol.timeline)
timeline = symbol.timeline;
classToCheck = classToCheck.superClass;
}
var name = (_d = (_c = (_b = (_a = _this.superClass) === null || _a === void 0 ? void 0 : _a.classInfo) === null || _b === void 0 ? void 0 : _b.instanceInfo) === null || _c === void 0 ? void 0 : _c.multiname) === null || _d === void 0 ? void 0 : _d.name;
var appDom;
if (_this.axApplicationDomain && _this.axApplicationDomain.awayApplicationDomain) {
appDom = _this.axApplicationDomain.awayApplicationDomain;
}
else if (ActiveLoaderContext.loaderContext) {
appDom = ActiveLoaderContext.loaderContext.applicationDomain;
}
var mn = _this.classInfo.instanceInfo.multiname;
var instName = mn.name;
var fullName = mn.uri ? mn.uri + '.' + instName : instName;
if (timeline) {
// type MUST BE AS MC, if it was a sprite - mc not will be generated
var isMovieClip = this.sec.flash.display.MovieClip.axIsType(object)
|| this.sec.flash.display.SimpleButton.axIsType(object);
if (!isMovieClip) {
//console.log('Class is not MC:', fullName);
}
var adaptee = new MovieClip(timeline, !isMovieClip);
object.adaptee = adaptee;
adaptee.reset();
FrameScriptManager.execute_as3_constructors_recursiv(adaptee);
}
if (!timeline && appDom && appDom.hasSymbolForClass(fullName)) {
var asset = appDom.getSymbolAdaptee(fullName);
if (!asset) {
// eslint-disable-next-line max-len
console.warn("error: could not get asset ".concat(name, " for class ").concat(instName, ", no ActiveLoaderContext.loaderContext"));
}
if (asset) {
if (asset instanceof MovieClip) {
object.adaptee.graphics = asset.graphics;
}
else {
object.adaptee = asset;
}
}
}
// @todo: this is a hack for getting adaptee
// for dynamic created SimpleButton
if (instName === 'SimpleButton') {
object.adaptee = new MovieClip(new Timeline(this.sec.player.factory));
}
// mark object that it is AX object, not a regular class
object[IS_AX_CLASS] = true;
// eslint-disable-next-line prefer-spread
object.axInitializer.apply(object, argArray);
object.constructorHasRun = true;
if (object.adaptee)
OrphanManager.addOrphan(object.adaptee);
if (object.isAVMFont) {
// hack for font: make sure the fontName is set on Font
object.fontName = instName;
}
return object;
}
var NEED_SLOW_CONSTRUCTOR = {
'MovieClip': true,
'DisplayObject': true,
'Sprite': true,
'Sound': true,
'SimpleButton': true,
'BitmapData': true
};
export function isFastConstructSupport(mn, trace) {
var classInfo = mn.abc.applicationDomain.findClassInfoDeep(mn);
// we not find class definition.. sorry
if (!classInfo) {
return false;
}
trace && trace.push(mn.name);
while (classInfo && mn) {
// This is special classes that require use slow constructor
if (NEED_SLOW_CONSTRUCTOR[mn.name]) {
return false;
}
mn = classInfo.instanceInfo.superName;
if (!mn) {
return true;
}
if (NEED_SLOW_CONSTRUCTOR[mn.name]) {
return false;
}
trace && trace.push(mn.name);
classInfo = mn.abc.applicationDomain.findClassInfoDeep(mn);
if (!classInfo) {
return true;
}
// top level class 'Object', all classes extends it and it not have super
if (mn.name === 'Object' && mn.namespace.uri === '' && !classInfo.instanceInfo.superName) {
return true;
}
}
// if we can't traverse - use slow
return false;
}
/**
* Fast version of axConstruct, must be called when we strictly
* know that elements not Interactive object and not have linked symbol,
* this can save a lot of time for check
*/
export function axConstructFast(ctor, args) {
var object = Object.create(ctor.tPrototype);
ctor.tPrototype.traits && initTraitsForObject(object, ctor.tPrototype.traits);
// mark object that it is AX object, not a regular class
object[IS_AX_CLASS] = true;
Reflect.apply(object.axInitializer, object, args);
object.constructorHasRun = true;
return object;
}