UNPKG

dragonbones-runtime

Version:

the tools to build dragonbones file for diffrent framework

590 lines (519 loc) 18.9 kB
////////////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2014-present, Egret Technology. // All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of the Egret nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY EGRET AND CONTRIBUTORS "AS IS" AND ANY EXPRESS // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL EGRET AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA, // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ////////////////////////////////////////////////////////////////////////////////////// namespace eui.sys { /** * @private * 失效验证管理器 */ export class Validator extends egret.EventDispatcher { /** * @private * 创建一个Validator对象 */ public constructor() { super(); } /** * @private */ private targetLevel:number = Number.POSITIVE_INFINITY; /** * @private */ private invalidatePropertiesFlag:boolean = false; /** * @private */ private invalidateClientPropertiesFlag:boolean = false; /** * @private */ private invalidatePropertiesQueue:DepthQueue = new DepthQueue(); /** * @private * 标记组件属性失效 */ public invalidateProperties(client:UIComponent):void { if (!this.invalidatePropertiesFlag) { this.invalidatePropertiesFlag = true; if (!this.listenersAttached) this.attachListeners(); } if (this.targetLevel <= client.$nestLevel) this.invalidateClientPropertiesFlag = true; this.invalidatePropertiesQueue.insert(client); } /** * @private * 验证失效的属性 */ private validateProperties():void { let queue = this.invalidatePropertiesQueue; let client:UIComponent = queue.shift(); while (client) { if (client.$stage) { client.validateProperties(); } client = queue.shift(); } if (queue.isEmpty()) this.invalidatePropertiesFlag = false; } /** * @private */ private invalidateSizeFlag:boolean = false; /** * @private */ private invalidateClientSizeFlag:boolean = false; /** * @private */ private invalidateSizeQueue:DepthQueue = new DepthQueue(); /** * @private * 标记需要重新测量尺寸 */ public invalidateSize(client:UIComponent):void { if (!this.invalidateSizeFlag) { this.invalidateSizeFlag = true; if (!this.listenersAttached) this.attachListeners(); } if (this.targetLevel <= client.$nestLevel) this.invalidateClientSizeFlag = true; this.invalidateSizeQueue.insert(client); } /** * @private * 测量尺寸 */ private validateSize():void { let queue = this.invalidateSizeQueue; let client:UIComponent = queue.pop(); while (client) { if (client.$stage) { client.validateSize(); } client = queue.pop(); } if (queue.isEmpty()) this.invalidateSizeFlag = false; } /** * @private */ private invalidateDisplayListFlag:boolean = false; /** * @private */ private invalidateDisplayListQueue:DepthQueue = new DepthQueue(); /** * @private * 标记需要重新布局 */ public invalidateDisplayList(client:UIComponent):void { if (!this.invalidateDisplayListFlag) { this.invalidateDisplayListFlag = true; if (!this.listenersAttached) this.attachListeners(); } this.invalidateDisplayListQueue.insert(client); } /** * @private * 重新布局 */ private validateDisplayList():void { let queue = this.invalidateDisplayListQueue; let client:UIComponent = queue.shift(); while (client) { if (client.$stage) { client.validateDisplayList(); } client = queue.shift(); } if (queue.isEmpty()) this.invalidateDisplayListFlag = false; } /** * @private */ private eventDisplay:egret.Bitmap = new egret.Bitmap(); /** * @private * 是否已经添加了事件监听 */ private listenersAttached:boolean = false; /** * @private * 添加事件监听 */ private attachListeners():void { this.eventDisplay.addEventListener(egret.Event.ENTER_FRAME, this.doPhasedInstantiationCallBack, this); this.eventDisplay.addEventListener(egret.Event.RENDER, this.doPhasedInstantiationCallBack, this); egret.sys.$invalidateRenderFlag = true; this.listenersAttached = true; } /** * @private * 执行属性应用 */ private doPhasedInstantiationCallBack(event?:egret.Event):void { this.eventDisplay.removeEventListener(egret.Event.ENTER_FRAME, this.doPhasedInstantiationCallBack, this); this.eventDisplay.removeEventListener(egret.Event.RENDER, this.doPhasedInstantiationCallBack, this); this.doPhasedInstantiation(); } /** * @private * */ private doPhasedInstantiation():void { if (this.invalidatePropertiesFlag) { this.validateProperties(); } if (this.invalidateSizeFlag) { this.validateSize(); } if (this.invalidateDisplayListFlag) { this.validateDisplayList(); } if (this.invalidatePropertiesFlag || this.invalidateSizeFlag || this.invalidateDisplayListFlag) { this.attachListeners(); } else { this.listenersAttached = false; } } /** * @private * 使大于等于指定组件层级的元素立即应用属性 * @param target 要立即应用属性的组件 */ public validateClient(target:UIComponent):void { let obj:UIComponent; let done = false; let oldTargetLevel = this.targetLevel; if (this.targetLevel === Number.POSITIVE_INFINITY) this.targetLevel = target.$nestLevel; let propertiesQueue = this.invalidatePropertiesQueue; let sizeQueue = this.invalidateSizeQueue; let displayListQueue = this.invalidateDisplayListQueue; while (!done) { done = true; obj = propertiesQueue.removeSmallestChild(target); while (obj) { if (obj.$stage) { obj.validateProperties(); } obj = propertiesQueue.removeSmallestChild(target); } if (propertiesQueue.isEmpty()) { this.invalidatePropertiesFlag = false; } this.invalidateClientPropertiesFlag = false; obj = sizeQueue.removeLargestChild(target); while (obj) { if (obj.$stage) { obj.validateSize(); } if (this.invalidateClientPropertiesFlag) { obj = <UIComponent> (propertiesQueue.removeSmallestChild(target)); if (obj) { propertiesQueue.insert(obj); done = false; break; } } obj = sizeQueue.removeLargestChild(target); } if (sizeQueue.isEmpty()) { this.invalidateSizeFlag = false; } this.invalidateClientPropertiesFlag = false; this.invalidateClientSizeFlag = false; obj = displayListQueue.removeSmallestChild(target); while (obj) { if (obj.$stage) { obj.validateDisplayList(); } if (this.invalidateClientPropertiesFlag) { obj = propertiesQueue.removeSmallestChild(target); if (obj) { propertiesQueue.insert(obj); done = false; break; } } if (this.invalidateClientSizeFlag) { obj =sizeQueue.removeLargestChild(target); if (obj) { sizeQueue.insert(obj); done = false; break; } } obj = displayListQueue.removeSmallestChild(target); } if (displayListQueue.isEmpty()) { this.invalidateDisplayListFlag = false; } } if (oldTargetLevel === Number.POSITIVE_INFINITY) { this.targetLevel = Number.POSITIVE_INFINITY; } } } /** * @private * 显示列表嵌套深度排序队列 */ class DepthQueue { /** * 深度队列 */ private depthBins:{[key:number]:DepthBin} = {}; /** * 最小深度 */ private minDepth:number = 0; /** * 最大深度 */ private maxDepth:number = -1; /** * 插入一个元素 */ public insert(client:UIComponent):void { let depth = client.$nestLevel; if (this.maxDepth < this.minDepth) { this.minDepth = this.maxDepth = depth; } else { if (depth < this.minDepth) this.minDepth = depth; if (depth > this.maxDepth) this.maxDepth = depth; } let bin = this.depthBins[depth]; if (!bin) { bin = this.depthBins[depth] = new DepthBin(); } bin.insert(client); } /** * 从队列尾弹出深度最大的一个对象 */ public pop():UIComponent { let client:UIComponent; let minDepth = this.minDepth; if (minDepth <= this.maxDepth) { let bin = this.depthBins[this.maxDepth]; while (!bin || bin.length === 0) { this.maxDepth--; if (this.maxDepth < minDepth) return null; bin = this.depthBins[this.maxDepth]; } client = bin.pop(); while (!bin || bin.length == 0) { this.maxDepth--; if (this.maxDepth < minDepth) break; bin = this.depthBins[this.maxDepth]; } } return client; } /** * 从队列首弹出深度最小的一个对象 */ public shift():UIComponent { let client:UIComponent; let maxDepth = this.maxDepth; if (this.minDepth <= maxDepth) { let bin = this.depthBins[this.minDepth]; while (!bin || bin.length === 0) { this.minDepth++; if (this.minDepth > maxDepth) return null; bin = this.depthBins[this.minDepth]; } client = bin.pop(); while (!bin || bin.length == 0) { this.minDepth++; if (this.minDepth > maxDepth) break; bin = this.depthBins[this.minDepth]; } } return client; } /** * 移除大于等于指定组件层级的元素中最大的元素 */ public removeLargestChild(client:UIComponent):UIComponent { let hashCode = client.$hashCode; let nestLevel = client.$nestLevel; let max = this.maxDepth; let min = nestLevel; while (min <= max) { let bin = this.depthBins[max]; if (bin && bin.length > 0) { if (max === nestLevel) { if (bin.map[hashCode]) { bin.remove(client); return client; } } else if(egret.is(client,"egret.DisplayObjectContainer")){ let items = bin.items; let length = bin.length; for (let i = 0; i < length; i++) { let value = items[i]; if ((<egret.DisplayObjectContainer><any> client).contains(value)) { bin.remove(value); return value; } } } else{ break; } max--; } else { if (max == this.maxDepth){ this.maxDepth--; } max--; if (max < min) break; } } return null; } /** * 移除大于等于指定组件层级的元素中最小的元素 */ public removeSmallestChild(client:UIComponent):UIComponent { let nestLevel = client.$nestLevel; let min = nestLevel; let max = this.maxDepth; let hashCode = client.$hashCode; while (min <= max) { let bin = this.depthBins[min]; if (bin && bin.length > 0) { if (min === nestLevel) { if (bin.map[hashCode]) { bin.remove(client); return client; } } else if(egret.is(client,"egret.DisplayObjectContainer")){ let items = bin.items; let length = bin.length; for (let i = 0; i < length; i++) { let value = items[i]; if ((<egret.DisplayObjectContainer><any> client).contains(value)) { bin.remove(value); return value; } } } else{ break; } min++; } else { if (min == this.minDepth) this.minDepth++; min++; if (min > max) break; } } return null; } /** * 队列是否为空 */ public isEmpty():boolean { return this.minDepth > this.maxDepth; } } /** * @private * 列表项 */ class DepthBin { public map:{[key:number]:boolean} = {}; public items:UIComponent[] = []; public length:number = 0; public insert(client:UIComponent):void { let hashCode = client.$hashCode; if (this.map[hashCode]) { return; } this.map[hashCode] = true; this.length++; this.items.push(client); } public pop():UIComponent { let client = this.items.pop();//使用pop会比shift有更高的性能,避免索引整体重置。 if (client) { this.length--; if(this.length===0){ this.map = {};//清空所有key防止内存泄露 } else{ this.map[client.$hashCode] = false; } } return client; } public remove(client:UIComponent):void { let index = this.items.indexOf(client); if (index >= 0) { this.items.splice(index, 1); this.length--; if(this.length===0){ this.map = {};//清空所有key防止内存泄露 } else{ this.map[client.$hashCode] = false; } } } } }