1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26WebInspector.LayerTreeManager = function() {
27    WebInspector.Object.call(this);
28
29    this._supported = !!window.LayerTreeAgent;
30
31    if (this._supported)
32        LayerTreeAgent.enable();
33};
34
35WebInspector.LayerTreeManager.Event = {
36    LayerTreeDidChange: "layer-tree-did-change"
37};
38
39WebInspector.LayerTreeManager.prototype = {
40    constructor: WebInspector.LayerTreeManager,
41
42    // Public
43
44    get supported()
45    {
46        return this._supported;
47    },
48
49    layerTreeMutations: function(previousLayers, newLayers)
50    {
51        console.assert(this.supported);
52
53        if (isEmptyObject(previousLayers)) {
54            return {
55                preserved: [],
56                additions: newLayers,
57                removals: []
58            };
59        }
60
61        function nodeIdForLayer(layer)
62        {
63            return layer.isGeneratedContent ? layer.pseudoElementId : layer.nodeId;
64        }
65
66        var layerIdsInPreviousLayers = [];
67        var nodeIdsInPreviousLayers = [];
68        var nodeIdsForReflectionsInPreviousLayers = [];
69
70        previousLayers.forEach(function(layer) {
71            layerIdsInPreviousLayers.push(layer.layerId);
72
73            var nodeId = nodeIdForLayer(layer);
74            if (!nodeId)
75                return;
76
77            if (layer.isReflection)
78                nodeIdsForReflectionsInPreviousLayers.push(nodeId);
79            else
80                nodeIdsInPreviousLayers.push(nodeId);
81        });
82
83        var preserved = [];
84        var additions = [];
85
86        var layerIdsInNewLayers = [];
87        var nodeIdsInNewLayers = [];
88        var nodeIdsForReflectionsInNewLayers = [];
89
90        newLayers.forEach(function(layer) {
91            layerIdsInNewLayers.push(layer.layerId);
92
93            var existed = layerIdsInPreviousLayers.contains(layer.layerId);
94
95            var nodeId = nodeIdForLayer(layer);
96            if (!nodeId)
97                return;
98
99            if (layer.isReflection) {
100                nodeIdsForReflectionsInNewLayers.push(nodeId);
101                existed = existed || nodeIdsForReflectionsInPreviousLayers.contains(nodeId);
102            } else {
103                nodeIdsInNewLayers.push(nodeId);
104                existed = existed || nodeIdsInPreviousLayers.contains(nodeId);
105            }
106
107            if (existed)
108                preserved.push(layer);
109            else
110                additions.push(layer);
111        });
112
113        var removals = previousLayers.filter(function(layer) {
114            var nodeId = nodeIdForLayer(layer);
115
116            if (layer.isReflection)
117                return !nodeIdsForReflectionsInNewLayers.contains(nodeId);
118            else
119                return !nodeIdsInNewLayers.contains(nodeId) && !layerIdsInNewLayers.contains(layer.layerId);
120        });
121
122        return {
123            preserved: preserved,
124            additions: additions,
125            removals: removals
126        };
127    },
128
129    layersForNode: function(node, callback)
130    {
131        console.assert(this.supported);
132
133        LayerTreeAgent.layersForNode(node.id, function(error, layers) {
134            if (error || isEmptyObject(layers)) {
135                callback(null, []);
136                return;
137            }
138
139            var firstLayer = layers[0];
140            var layerForNode = firstLayer.nodeId === node.id && !firstLayer.isGeneratedContent ? layers.shift() : null;
141            callback(layerForNode, layers);
142        }.bind(this));
143    },
144
145    reasonsForCompositingLayer: function(layer, callback)
146    {
147        console.assert(this.supported);
148
149        LayerTreeAgent.reasonsForCompositingLayer(layer.layerId, function(error, reasons) {
150            callback(error ? 0 : reasons);
151        });
152    },
153
154    layerTreeDidChange: function()
155    {
156        this.dispatchEventToListeners(WebInspector.LayerTreeManager.Event.LayerTreeDidChange);
157    }
158};
159
160WebInspector.LayerTreeManager.prototype.__proto__ = WebInspector.Object.prototype;
161