1/*
2 * Copyright (C) 2012 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 are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32
33#if USE(ACCELERATED_COMPOSITING)
34#if ENABLE(INSPECTOR)
35
36#include "InspectorLayerTreeAgent.h"
37
38#include "IdentifiersFactory.h"
39#include "InspectorDOMAgent.h"
40#include "InspectorFrontend.h"
41#include "InspectorState.h"
42#include "InstrumentingAgents.h"
43#include "IntRect.h"
44#include "PseudoElement.h"
45#include "RenderLayer.h"
46#include "RenderLayerBacking.h"
47#include "RenderLayerCompositor.h"
48#include "RenderView.h"
49
50namespace WebCore {
51
52namespace LayerTreeAgentState {
53static const char layerTreeAgentEnabled[] = "layerTreeAgentEnabled";
54};
55
56InspectorLayerTreeAgent::InspectorLayerTreeAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state)
57    : InspectorBaseAgent<InspectorLayerTreeAgent>("LayerTree", instrumentingAgents, state)
58    , m_frontend(0)
59{
60}
61
62InspectorLayerTreeAgent::~InspectorLayerTreeAgent()
63{
64    reset();
65}
66
67void InspectorLayerTreeAgent::setFrontend(InspectorFrontend* frontend)
68{
69    m_frontend = frontend->layertree();
70}
71
72void InspectorLayerTreeAgent::clearFrontend()
73{
74    m_frontend = 0;
75    disable(0);
76}
77
78void InspectorLayerTreeAgent::restore()
79{
80    if (m_state->getBoolean(LayerTreeAgentState::layerTreeAgentEnabled))
81        enable(0);
82}
83
84void InspectorLayerTreeAgent::reset()
85{
86    m_documentLayerToIdMap.clear();
87    m_idToLayer.clear();
88    m_pseudoElementToIdMap.clear();
89    m_idToPseudoElement.clear();
90}
91
92void InspectorLayerTreeAgent::enable(ErrorString*)
93{
94    m_state->setBoolean(LayerTreeAgentState::layerTreeAgentEnabled, true);
95    m_instrumentingAgents->setInspectorLayerTreeAgent(this);
96}
97
98void InspectorLayerTreeAgent::disable(ErrorString*)
99{
100    if (!m_state->getBoolean(LayerTreeAgentState::layerTreeAgentEnabled))
101        return;
102    m_state->setBoolean(LayerTreeAgentState::layerTreeAgentEnabled, false);
103    m_instrumentingAgents->setInspectorLayerTreeAgent(0);
104}
105
106void InspectorLayerTreeAgent::layerTreeDidChange()
107{
108    m_frontend->layerTreeDidChange();
109}
110
111void InspectorLayerTreeAgent::renderLayerDestroyed(const RenderLayer* renderLayer)
112{
113    unbind(renderLayer);
114}
115
116void InspectorLayerTreeAgent::pseudoElementDestroyed(PseudoElement* pseudoElement)
117{
118    unbindPseudoElement(pseudoElement);
119}
120
121void InspectorLayerTreeAgent::layersForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
122{
123    layers = TypeBuilder::Array<TypeBuilder::LayerTree::Layer>::create();
124
125    Node* node = m_instrumentingAgents->inspectorDOMAgent()->nodeForId(nodeId);
126    if (!node) {
127        *errorString = "Provided node id doesn't match any known node";
128        return;
129    }
130
131    RenderObject* renderer = node->renderer();
132    if (!renderer) {
133        *errorString = "Node for provided node id doesn't have a renderer";
134        return;
135    }
136
137    gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers);
138}
139
140void InspectorLayerTreeAgent::gatherLayersUsingRenderObjectHierarchy(ErrorString* errorString, RenderObject* renderer, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
141{
142    if (renderer->hasLayer()) {
143        gatherLayersUsingRenderLayerHierarchy(errorString, toRenderLayerModelObject(renderer)->layer(), layers);
144        return;
145    }
146
147    for (renderer = renderer->firstChild(); renderer; renderer = renderer->nextSibling())
148        gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers);
149}
150
151void InspectorLayerTreeAgent::gatherLayersUsingRenderLayerHierarchy(ErrorString* errorString, RenderLayer* renderLayer, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
152{
153    if (renderLayer->isComposited())
154        layers->addItem(buildObjectForLayer(errorString, renderLayer));
155
156    for (renderLayer = renderLayer->firstChild(); renderLayer; renderLayer = renderLayer->nextSibling())
157        gatherLayersUsingRenderLayerHierarchy(errorString, renderLayer, layers);
158}
159
160PassRefPtr<TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForLayer(ErrorString* errorString, RenderLayer* renderLayer)
161{
162    RenderObject* renderer = renderLayer->renderer();
163    RenderLayerBacking* backing = renderLayer->backing();
164    Node* node = renderer->node();
165
166    bool isReflection = renderLayer->isReflection();
167    bool isGenerated = (isReflection ? renderer->parent() : renderer)->isBeforeOrAfterContent();
168    bool isAnonymous = renderer->isAnonymous();
169
170    if (isReflection && isGenerated)
171        node = renderer->parent()->generatingNode();
172    else if (isGenerated)
173        node = renderer->generatingNode();
174    else if (isReflection || isAnonymous)
175        node = renderer->parent()->node();
176
177    // Basic set of properties.
178    RefPtr<TypeBuilder::LayerTree::Layer> layerObject = TypeBuilder::LayerTree::Layer::create()
179        .setLayerId(bind(renderLayer))
180        .setNodeId(idForNode(errorString, node))
181        .setBounds(buildObjectForIntRect(renderer->absoluteBoundingBoxRect()))
182        .setMemory(backing->backingStoreMemoryEstimate())
183        .setCompositedBounds(buildObjectForIntRect(backing->compositedBounds()))
184        .setPaintCount(backing->graphicsLayer()->repaintCount());
185
186    if (node && node->shadowHost())
187        layerObject->setIsInShadowTree(true);
188
189    if (isReflection)
190        layerObject->setIsReflection(true);
191
192    if (isGenerated) {
193        if (isReflection)
194            renderer = renderer->parent();
195        layerObject->setIsGeneratedContent(true);
196        layerObject->setPseudoElementId(bindPseudoElement(static_cast<PseudoElement*>(renderer->node())));
197        if (renderer->isBeforeContent())
198            layerObject->setPseudoElement("before");
199        else if (renderer->isAfterContent())
200            layerObject->setPseudoElement("after");
201    }
202
203    if (isAnonymous) {
204        layerObject->setIsAnonymous(true);
205        if (RenderStyle* style = renderer->style()) {
206            if (style->styleType() == FIRST_LETTER)
207                layerObject->setPseudoElement("first-letter");
208            else if (style->styleType() == FIRST_LINE)
209                layerObject->setPseudoElement("first-line");
210        }
211    }
212
213    return layerObject;
214}
215
216int InspectorLayerTreeAgent::idForNode(ErrorString* errorString, Node* node)
217{
218    if (!node)
219        return 0;
220
221    InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent();
222
223    int nodeId = domAgent->boundNodeId(node);
224    if (!nodeId)
225        nodeId = domAgent->pushNodeToFrontend(errorString, domAgent->boundNodeId(node->document()), node);
226
227    return nodeId;
228}
229
230PassRefPtr<TypeBuilder::LayerTree::IntRect> InspectorLayerTreeAgent::buildObjectForIntRect(const IntRect& rect)
231{
232    return TypeBuilder::LayerTree::IntRect::create()
233        .setX(rect.x())
234        .setY(rect.y())
235        .setWidth(rect.width())
236        .setHeight(rect.height()).release();
237}
238
239void InspectorLayerTreeAgent::reasonsForCompositingLayer(ErrorString* errorString, const String& layerId, RefPtr<TypeBuilder::LayerTree::CompositingReasons>& compositingReasons)
240{
241    const RenderLayer* renderLayer = m_idToLayer.get(layerId);
242
243    if (!renderLayer) {
244        *errorString = "Could not find a bound layer for the provided id";
245        return;
246    }
247
248    CompositingReasons reasonsBitmask = renderLayer->compositor()->reasonsForCompositing(renderLayer);
249    compositingReasons = TypeBuilder::LayerTree::CompositingReasons::create();
250
251    if (reasonsBitmask & CompositingReason3DTransform)
252        compositingReasons->setTransform3D(true);
253
254    if (reasonsBitmask & CompositingReasonVideo)
255        compositingReasons->setVideo(true);
256
257    if (reasonsBitmask & CompositingReasonCanvas)
258        compositingReasons->setCanvas(true);
259
260    if (reasonsBitmask & CompositingReasonPlugin)
261        compositingReasons->setPlugin(true);
262
263    if (reasonsBitmask & CompositingReasonIFrame)
264        compositingReasons->setIFrame(true);
265
266    if (reasonsBitmask & CompositingReasonBackfaceVisibilityHidden)
267        compositingReasons->setBackfaceVisibilityHidden(true);
268
269    if (reasonsBitmask & CompositingReasonClipsCompositingDescendants)
270        compositingReasons->setClipsCompositingDescendants(true);
271
272    if (reasonsBitmask & CompositingReasonAnimation)
273        compositingReasons->setAnimation(true);
274
275    if (reasonsBitmask & CompositingReasonFilters)
276        compositingReasons->setFilters(true);
277
278    if (reasonsBitmask & CompositingReasonPositionFixed)
279        compositingReasons->setPositionFixed(true);
280
281    if (reasonsBitmask & CompositingReasonPositionSticky)
282        compositingReasons->setPositionSticky(true);
283
284    if (reasonsBitmask & CompositingReasonOverflowScrollingTouch)
285        compositingReasons->setOverflowScrollingTouch(true);
286
287    if (reasonsBitmask & CompositingReasonStacking)
288        compositingReasons->setStacking(true);
289
290    if (reasonsBitmask & CompositingReasonOverlap)
291        compositingReasons->setOverlap(true);
292
293    if (reasonsBitmask & CompositingReasonNegativeZIndexChildren)
294        compositingReasons->setNegativeZIndexChildren(true);
295
296    if (reasonsBitmask & CompositingReasonTransformWithCompositedDescendants)
297        compositingReasons->setTransformWithCompositedDescendants(true);
298
299    if (reasonsBitmask & CompositingReasonOpacityWithCompositedDescendants)
300        compositingReasons->setOpacityWithCompositedDescendants(true);
301
302    if (reasonsBitmask & CompositingReasonMaskWithCompositedDescendants)
303        compositingReasons->setMaskWithCompositedDescendants(true);
304
305    if (reasonsBitmask & CompositingReasonReflectionWithCompositedDescendants)
306        compositingReasons->setReflectionWithCompositedDescendants(true);
307
308    if (reasonsBitmask & CompositingReasonFilterWithCompositedDescendants)
309        compositingReasons->setFilterWithCompositedDescendants(true);
310
311    if (reasonsBitmask & CompositingReasonBlendingWithCompositedDescendants)
312        compositingReasons->setBlendingWithCompositedDescendants(true);
313
314    if (reasonsBitmask & CompositingReasonPerspective)
315        compositingReasons->setPerspective(true);
316
317    if (reasonsBitmask & CompositingReasonPreserve3D)
318        compositingReasons->setPreserve3D(true);
319
320    if (reasonsBitmask & CompositingReasonRoot)
321        compositingReasons->setRoot(true);
322}
323
324String InspectorLayerTreeAgent::bind(const RenderLayer* layer)
325{
326    if (!layer)
327        return emptyString();
328    String identifier = m_documentLayerToIdMap.get(layer);
329    if (identifier.isNull()) {
330        identifier = IdentifiersFactory::createIdentifier();
331        m_documentLayerToIdMap.set(layer, identifier);
332        m_idToLayer.set(identifier, layer);
333    }
334    return identifier;
335}
336
337void InspectorLayerTreeAgent::unbind(const RenderLayer* layer)
338{
339    HashMap<const RenderLayer*, String>::iterator iterator = m_documentLayerToIdMap.find(layer);
340    if (iterator == m_documentLayerToIdMap.end())
341        return;
342    m_idToLayer.remove(iterator->value);
343    m_documentLayerToIdMap.remove(iterator);
344}
345
346String InspectorLayerTreeAgent::bindPseudoElement(PseudoElement* pseudoElement)
347{
348    if (!pseudoElement)
349        return emptyString();
350    String identifier = m_pseudoElementToIdMap.get(pseudoElement);
351    if (identifier.isNull()) {
352        identifier = IdentifiersFactory::createIdentifier();
353        m_pseudoElementToIdMap.set(pseudoElement, identifier);
354        m_idToPseudoElement.set(identifier, pseudoElement);
355    }
356    return identifier;
357}
358
359void InspectorLayerTreeAgent::unbindPseudoElement(PseudoElement* pseudoElement)
360{
361    HashMap<PseudoElement*, String>::iterator iterator = m_pseudoElementToIdMap.find(pseudoElement);
362    if (iterator == m_pseudoElementToIdMap.end())
363        return;
364    m_idToPseudoElement.remove(iterator->value);
365    m_pseudoElementToIdMap.remove(iterator);
366}
367
368} // namespace WebCore
369
370#endif // ENABLE(INSPECTOR)
371#endif // USE(ACCELERATED_COMPOSITING)
372