UNPKG

@awayfl/avm2

Version:

Virtual machine for executing AS3 code

218 lines (217 loc) 8.07 kB
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; }