| /* |
| * Copyright (C) 2013 Google Inc. 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 Google Inc. 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 THE COPYRIGHT HOLDERS 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 THE COPYRIGHT |
| * OWNER OR 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. |
| */ |
| |
| /** |
| * @constructor |
| * @extends {WebInspector.Object} |
| */ |
| WebInspector.LayerTreeModel = function() |
| { |
| WebInspector.Object.call(this); |
| this._layersById = {}; |
| InspectorBackend.registerLayerTreeDispatcher(new WebInspector.LayerTreeDispatcher(this)); |
| LayerTreeAgent.enable(); |
| this._needsRefresh = true; |
| } |
| |
| WebInspector.LayerTreeModel.Events = { |
| LayerTreeChanged: "LayerTreeChanged", |
| } |
| |
| WebInspector.LayerTreeModel.prototype = { |
| dispose: function() |
| { |
| LayerTreeAgent.disable(); |
| }, |
| |
| /** |
| * @return {WebInspector.Layer} |
| */ |
| root: function() |
| { |
| return this._root; |
| }, |
| |
| /** |
| * @param {function(WebInspector.Layer)} callback |
| * @param {WebInspector.Layer=} root |
| * @return {boolean} |
| */ |
| forEachLayer: function(callback, root) |
| { |
| if (!root) { |
| root = this.root(); |
| if (!root) |
| return false; |
| } |
| return callback(root) || root.children().some(this.forEachLayer.bind(this, callback)); |
| }, |
| |
| /** |
| * @param {function()=} callback |
| */ |
| requestLayers: function(callback) |
| { |
| delete this._delayedRequestLayersTimer; |
| if (!callback) |
| callback = function() {} |
| if (!this._needsRefresh) { |
| callback(); |
| return; |
| } |
| if (this._pendingRequestLayersCallbacks) { |
| this._pendingRequestLayersCallbacks.push(callback); |
| return; |
| } |
| this._pendingRequestLayersCallbacks = []; |
| this._pendingRequestLayersCallbacks.push(callback); |
| function onGetLayers(error, layers) |
| { |
| this._root = null; |
| if (error) { |
| console.error("LayerTreeAgent.getLayers(): " + error); |
| return; |
| } |
| this._repopulate(layers); |
| for (var i = 0; i < this._pendingRequestLayersCallbacks.length; ++i) |
| this._pendingRequestLayersCallbacks[i](); |
| delete this._pendingRequestLayersCallbacks; |
| } |
| function onDocumentAvailable() |
| { |
| LayerTreeAgent.getLayers(undefined, onGetLayers.bind(this)) |
| } |
| WebInspector.domAgent.requestDocument(onDocumentAvailable.bind(this)); |
| }, |
| |
| /** |
| * @param {string} id |
| * @return {WebInspector.Layer?} |
| */ |
| layerById: function(id) |
| { |
| return this._layersById[id]; |
| }, |
| |
| /** |
| * @param{Array.<LayerTreeAgent.Layer>} payload |
| */ |
| _repopulate: function(payload) |
| { |
| var oldLayersById = this._layersById; |
| this._layersById = {}; |
| for (var i = 0; i < payload.length; ++i) { |
| var layer = oldLayersById[payload[i].layerId]; |
| if (layer) |
| layer._reset(payload[i]); |
| else |
| layer = new WebInspector.Layer(payload[i]); |
| this._layersById[layer.id()] = layer; |
| var parentId = layer.parentId(); |
| if (parentId) |
| this._layersById[parentId].addChild(layer); |
| else { |
| if (this._root) |
| console.assert(false, "Multiple root layers"); |
| this._root = layer; |
| } |
| } |
| this.dispatchEventToListeners(WebInspector.LayerTreeModel.Events.LayerTreeChanged); |
| }, |
| |
| _layerTreeChanged: function() |
| { |
| if (this._delayedRequestLayersTimer) |
| return; |
| this._needsRefresh = true; |
| this._delayedRequestLayersTimer = setTimeout(this.requestLayers.bind(this), 100); |
| }, |
| |
| __proto__: WebInspector.Object.prototype |
| } |
| |
| /** |
| * @constructor |
| * @param {LayerTreeAgent.Layer} layerPayload |
| */ |
| WebInspector.Layer = function(layerPayload) |
| { |
| this._reset(layerPayload); |
| } |
| |
| WebInspector.Layer.prototype = { |
| /** |
| * @return {string?} |
| */ |
| id: function() |
| { |
| return this._layerPayload.layerId; |
| }, |
| |
| /** |
| * @return {string?} |
| */ |
| parentId: function() |
| { |
| return this._layerPayload.parentLayerId; |
| }, |
| |
| /** |
| * @return {WebInspector.Layer} |
| */ |
| parent: function() |
| { |
| return this._parent; |
| }, |
| |
| /** |
| * @return {boolean} |
| */ |
| isRoot: function() |
| { |
| return !!this.parentId(); |
| }, |
| |
| /** |
| * @return {Array.<WebInspector.Layer>} |
| */ |
| children: function() |
| { |
| return this._children; |
| }, |
| |
| /** |
| * @param {WebInspector.Layer} child |
| */ |
| addChild: function(child) |
| { |
| if (child._parent) |
| console.assert(false, "Child already has a parent"); |
| this._children.push(child); |
| child._parent = this; |
| }, |
| |
| /** |
| * @return {DOMAgent.NodeId?} |
| */ |
| nodeId: function() |
| { |
| return this._layerPayload.nodeId; |
| }, |
| |
| /** |
| * @return {DOMAgent.NodeId?} |
| */ |
| nodeIdForSelfOrAncestor: function() |
| { |
| for (var layer = this; layer; layer = layer._parent) { |
| var nodeId = layer._layerPayload.nodeId; |
| if (nodeId) |
| return nodeId; |
| } |
| return null; |
| }, |
| |
| /** |
| * @return {number} |
| */ |
| offsetX: function() |
| { |
| return this._layerPayload.offsetX; |
| }, |
| |
| /** |
| * @return {number} |
| */ |
| offsetY: function() |
| { |
| return this._layerPayload.offsetY; |
| }, |
| |
| /** |
| * @return {number} |
| */ |
| width: function() |
| { |
| return this._layerPayload.width; |
| }, |
| |
| /** |
| * @return {number} |
| */ |
| height: function() |
| { |
| return this._layerPayload.height; |
| }, |
| |
| /** |
| * @return {Array.<number>} |
| */ |
| transform: function() |
| { |
| return this._layerPayload.transform; |
| }, |
| |
| /** |
| * @return {Array.<number>} |
| */ |
| anchorPoint: function() |
| { |
| return [ |
| this._layerPayload.anchorX || 0, |
| this._layerPayload.anchorY || 0, |
| this._layerPayload.anchorZ || 0, |
| ]; |
| }, |
| |
| /** |
| * @param {LayerTreeAgent.Layer} layerPayload |
| */ |
| _reset: function(layerPayload) |
| { |
| this._children = []; |
| this._parent = null; |
| this._layerPayload = layerPayload; |
| } |
| } |
| |
| /** |
| * @constructor |
| * @implements {LayerTreeAgent.Dispatcher} |
| * @param {WebInspector.LayerTreeModel} layerTreeModel |
| */ |
| WebInspector.LayerTreeDispatcher = function(layerTreeModel) |
| { |
| this._layerTreeModel = layerTreeModel; |
| } |
| |
| WebInspector.LayerTreeDispatcher.prototype = { |
| layerTreeDidChange: function() |
| { |
| this._layerTreeModel._layerTreeChanged(); |
| } |
| } |