import { IDisplayObjectAdapter, DisplayObject } from "@awayjs/scene"; import { IAVM1Context, AVM1PropertyFlags, alToString, alIsName, IAVM1Callable, AVM1DefaultValueHint, alIsFunction } from "../runtime"; import { IAsset } from "@awayjs/core"; import { AVM1Context } from "../context"; import { release, Debug } from "../../base/utilities/Debug"; import { AVM1PropertyDescriptor } from "./AVM1PropertyDescriptor"; /** * Base class for object instances we prefer to not inherit Object.prototype properties. */ export class NullPrototypeObject { } var DEBUG_PROPERTY_PREFIX = '$Bg'; /** * Base class for the ActionScript AVM1 object. */ export class AVM1Object extends NullPrototypeObject implements IDisplayObjectAdapter { // Using our own bag of properties public _ownProperties: any; public _prototype: AVM1Object; public _avm1Context: IAVM1Context; public adaptee: IAsset; public avmType: string; protected initialDepth:number=0; protected scriptRefsToChilds:any={}; public _eventObserver:AVM1Object; public _blockedByScript:boolean; public _ctBlockedByScript:boolean; public protoTypeChanged:boolean; protected _visibilityByScript:boolean; public get eventObserver():AVM1Object{ return this._eventObserver; } public set eventObserver(value:AVM1Object){ this._eventObserver=value; } public dispose(): any{ } public isBlockedByScript():boolean{ return this._blockedByScript; } public isColorTransformByScript():boolean{ return this._ctBlockedByScript; } public isVisibilityByScript():boolean{ return this._visibilityByScript; } public initAdapter():void { } public freeFromScript():void{ this.protoTypeChanged=false; this._blockedByScript=false; this._ctBlockedByScript=false; this._visibilityByScript=false; } public clone(){ var newAVM1Object:AVM1Object=new AVM1Object(this._avm1Context); return newAVM1Object; } public get context(): AVM1Context { // too painful to have it as IAVM1Context return this._avm1Context; } public constructor(avm1Context: IAVM1Context) { super(); this._avm1Context = avm1Context; this._ownProperties = Object.create(null); this.scriptRefsToChilds={}; this._prototype = null; this._blockedByScript=false; this._ctBlockedByScript=false; this._visibilityByScript=false; var self = this; // Using IAVM1Callable here to avoid circular calls between AVM1Object and // AVM1Function during constructions. // TODO do we need to support __proto__ for all SWF versions? var getter = { alCall: function (thisArg: any, args?: any[]): any { return self.alPrototype; }}; var setter = { alCall: function (thisArg: any, args?: any[]): any { self.alPrototype = args[0]; }}; var desc = new AVM1PropertyDescriptor(AVM1PropertyFlags.ACCESSOR | AVM1PropertyFlags.DONT_DELETE | AVM1PropertyFlags.DONT_ENUM, null, getter, setter); this.alSetOwnProperty('__proto__', desc); } get alPrototype(): AVM1Object { return this._prototype; } set alPrototype(v: AVM1Object) { // checking for circular references var p = v; while (p) { if (p === this) { return; // possible loop in __proto__ chain is found } p = p.alPrototype; } // TODO recursive chain check this._prototype = v; } public alGetPrototypeProperty(): AVM1Object { return this.alGet('prototype'); } // TODO shall we add mode for readonly/native flags of the prototype property? public alSetOwnPrototypeProperty(v: any): void { this.alSetOwnProperty('prototype', new AVM1PropertyDescriptor(AVM1PropertyFlags.DATA | AVM1PropertyFlags.DONT_ENUM, v)); } public alGetConstructorProperty(): AVM1Object { return this.alGet('__constructor__'); } public alSetOwnConstructorProperty(v: any): void { this.alSetOwnProperty('__constructor__', new AVM1PropertyDescriptor(AVM1PropertyFlags.DATA | AVM1PropertyFlags.DONT_ENUM, v)); } _debugEscapeProperty(p: any): string { var context = this.context; var name = alToString(context, p); if (!context.isPropertyCaseSensitive) { name = name.toLowerCase(); } return DEBUG_PROPERTY_PREFIX + name; } public alGetOwnProperty(name): AVM1PropertyDescriptor { if (typeof name === 'string' && !this.context.isPropertyCaseSensitive) { name = name.toLowerCase(); } release || Debug.assert(alIsName(this.context, name)); // TODO __resolve return this._ownProperties[name]; } public alSetOwnProperty(p, desc: AVM1PropertyDescriptor): void { var name = this.context.normalizeName(p); if (!desc.originalName && !this.context.isPropertyCaseSensitive) { desc.originalName = p; } if (!release) { Debug.assert(desc instanceof AVM1PropertyDescriptor); // Ensure that a descriptor isn't used multiple times. If it were, we couldn't update // values in-place. Debug.assert(!desc['owningObject'] || desc['owningObject'] === this); desc['owningObject'] = this; // adding data property on the main object for convenience of debugging. if ((desc.flags & AVM1PropertyFlags.DATA) && !(desc.flags & AVM1PropertyFlags.DONT_ENUM)) { Object.defineProperty(this, this._debugEscapeProperty(name), {value: desc.value, enumerable: true, configurable: true}); } } this._ownProperties[name] = desc; } public alHasOwnProperty(p): boolean { var name = this.context.normalizeName(p); return !!this._ownProperties[name]; } public alDeleteOwnProperty(p) { var name = this.context.normalizeName(p); delete this._ownProperties[name]; if (!release) { delete this[this._debugEscapeProperty(p)]; } } public deleteOwnProperties() { var allProps=this.alGetOwnPropertiesKeys(); for(var i=0;i