dragonbones-runtime
Version:
the tools to build dragonbones file for diffrent framework
590 lines (519 loc) • 18.9 kB
text/typescript
//////////////////////////////////////////////////////////////////////////////////////
//
// 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;
}
}
}
}
}