f6e41fac828ac6c4f776065adf7a3dbf8d78be04
[WebKit-https.git] / Source / WebCore / inspector / InspectorLayerTreeAgent.cpp
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 #include "InspectorLayerTreeAgent.h"
33
34 #include "InspectorDOMAgent.h"
35 #include <inspector/InspectorFrontendDispatchers.h>
36 #include "InstrumentingAgents.h"
37 #include "IntRect.h"
38 #include "PseudoElement.h"
39 #include "RenderLayer.h"
40 #include "RenderLayerBacking.h"
41 #include "RenderLayerCompositor.h"
42 #include "RenderView.h"
43 #include <inspector/IdentifiersFactory.h>
44
45 using namespace Inspector;
46
47 namespace WebCore {
48
49 InspectorLayerTreeAgent::InspectorLayerTreeAgent(InstrumentingAgents* instrumentingAgents)
50     : InspectorAgentBase(ASCIILiteral("LayerTree"), instrumentingAgents)
51 {
52 }
53
54 InspectorLayerTreeAgent::~InspectorLayerTreeAgent()
55 {
56     reset();
57 }
58
59 void InspectorLayerTreeAgent::didCreateFrontendAndBackend(Inspector::FrontendChannel* frontendChannel, Inspector::BackendDispatcher* backendDispatcher)
60 {
61     m_frontendDispatcher = std::make_unique<Inspector::LayerTreeFrontendDispatcher>(frontendChannel);
62     m_backendDispatcher = Inspector::LayerTreeBackendDispatcher::create(backendDispatcher, this);
63 }
64
65 void InspectorLayerTreeAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
66 {
67     m_frontendDispatcher = nullptr;
68     m_backendDispatcher = nullptr;
69
70     ErrorString unused;
71     disable(unused);
72 }
73
74 void InspectorLayerTreeAgent::reset()
75 {
76     m_documentLayerToIdMap.clear();
77     m_idToLayer.clear();
78     m_pseudoElementToIdMap.clear();
79     m_idToPseudoElement.clear();
80 }
81
82 void InspectorLayerTreeAgent::enable(ErrorString&)
83 {
84     m_instrumentingAgents->setInspectorLayerTreeAgent(this);
85 }
86
87 void InspectorLayerTreeAgent::disable(ErrorString&)
88 {
89     m_instrumentingAgents->setInspectorLayerTreeAgent(nullptr);
90 }
91
92 void InspectorLayerTreeAgent::layerTreeDidChange()
93 {
94     m_frontendDispatcher->layerTreeDidChange();
95 }
96
97 void InspectorLayerTreeAgent::renderLayerDestroyed(const RenderLayer& renderLayer)
98 {
99     unbind(&renderLayer);
100 }
101
102 void InspectorLayerTreeAgent::pseudoElementDestroyed(PseudoElement& pseudoElement)
103 {
104     unbindPseudoElement(&pseudoElement);
105 }
106
107 void InspectorLayerTreeAgent::layersForNode(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::LayerTree::Layer>>& layers)
108 {
109     layers = Inspector::Protocol::Array<Inspector::Protocol::LayerTree::Layer>::create();
110
111     Node* node = m_instrumentingAgents->inspectorDOMAgent()->nodeForId(nodeId);
112     if (!node) {
113         errorString = ASCIILiteral("Provided node id doesn't match any known node");
114         return;
115     }
116
117     RenderObject* renderer = node->renderer();
118     if (!renderer) {
119         errorString = ASCIILiteral("Node for provided node id doesn't have a renderer");
120         return;
121     }
122
123     gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers);
124 }
125
126 void InspectorLayerTreeAgent::gatherLayersUsingRenderObjectHierarchy(ErrorString& errorString, RenderObject* renderer, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::LayerTree::Layer>>& layers)
127 {
128     if (renderer->hasLayer()) {
129         gatherLayersUsingRenderLayerHierarchy(errorString, downcast<RenderLayerModelObject>(*renderer).layer(), layers);
130         return;
131     }
132
133     for (renderer = renderer->firstChildSlow(); renderer; renderer = renderer->nextSibling())
134         gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers);
135 }
136
137 void InspectorLayerTreeAgent::gatherLayersUsingRenderLayerHierarchy(ErrorString& errorString, RenderLayer* renderLayer, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::LayerTree::Layer>>& layers)
138 {
139     if (renderLayer->isComposited())
140         layers->addItem(buildObjectForLayer(errorString, renderLayer));
141
142     for (renderLayer = renderLayer->firstChild(); renderLayer; renderLayer = renderLayer->nextSibling())
143         gatherLayersUsingRenderLayerHierarchy(errorString, renderLayer, layers);
144 }
145
146 Ref<Inspector::Protocol::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForLayer(ErrorString& errorString, RenderLayer* renderLayer)
147 {
148     RenderObject* renderer = &renderLayer->renderer();
149     RenderLayerBacking* backing = renderLayer->backing();
150     Node* node = renderer->node();
151
152     bool isReflection = renderLayer->isReflection();
153     bool isGenerated = (isReflection ? renderer->parent() : renderer)->isBeforeOrAfterContent();
154     bool isAnonymous = renderer->isAnonymous();
155
156     if (renderer->isRenderView())
157         node = &renderer->document();
158     else if (isReflection && isGenerated)
159         node = renderer->parent()->generatingElement();
160     else if (isGenerated)
161         node = renderer->generatingNode();
162     else if (isReflection || isAnonymous)
163         node = renderer->parent()->element();
164
165     // Basic set of properties.
166     auto layerObject = Inspector::Protocol::LayerTree::Layer::create()
167         .setLayerId(bind(renderLayer))
168         .setNodeId(idForNode(errorString, node))
169         .setBounds(buildObjectForIntRect(renderer->absoluteBoundingBoxRect()))
170         .setMemory(backing->backingStoreMemoryEstimate())
171         .setCompositedBounds(buildObjectForIntRect(enclosingIntRect(backing->compositedBounds())))
172         .setPaintCount(backing->graphicsLayer()->repaintCount())
173         .release();
174
175     if (node && node->shadowHost())
176         layerObject->setIsInShadowTree(true);
177
178     if (isReflection)
179         layerObject->setIsReflection(true);
180
181     if (isGenerated) {
182         if (isReflection)
183             renderer = renderer->parent();
184         layerObject->setIsGeneratedContent(true);
185         layerObject->setPseudoElementId(bindPseudoElement(downcast<PseudoElement>(renderer->node())));
186         if (renderer->isBeforeContent())
187             layerObject->setPseudoElement("before");
188         else if (renderer->isAfterContent())
189             layerObject->setPseudoElement("after");
190     }
191
192     // FIXME: RenderView is now really anonymous but don't tell about it to the frontend before making sure it can handle it.
193     if (isAnonymous && !renderer->isRenderView()) {
194         layerObject->setIsAnonymous(true);
195         const RenderStyle& style = renderer->style();
196         if (style.styleType() == FIRST_LETTER)
197             layerObject->setPseudoElement("first-letter");
198         else if (style.styleType() == FIRST_LINE)
199             layerObject->setPseudoElement("first-line");
200     }
201
202     return WTF::move(layerObject);
203 }
204
205 int InspectorLayerTreeAgent::idForNode(ErrorString& errorString, Node* node)
206 {
207     if (!node)
208         return 0;
209
210     InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent();
211     
212     int nodeId = domAgent->boundNodeId(node);
213     if (!nodeId)
214         nodeId = domAgent->pushNodeToFrontend(errorString, domAgent->boundNodeId(&node->document()), node);
215
216     return nodeId;
217 }
218
219 Ref<Inspector::Protocol::LayerTree::IntRect> InspectorLayerTreeAgent::buildObjectForIntRect(const IntRect& rect)
220 {
221     return Inspector::Protocol::LayerTree::IntRect::create()
222         .setX(rect.x())
223         .setY(rect.y())
224         .setWidth(rect.width())
225         .setHeight(rect.height())
226         .release();
227 }
228
229 void InspectorLayerTreeAgent::reasonsForCompositingLayer(ErrorString& errorString, const String& layerId, RefPtr<Inspector::Protocol::LayerTree::CompositingReasons>& compositingReasonsResult)
230 {
231     const RenderLayer* renderLayer = m_idToLayer.get(layerId);
232
233     if (!renderLayer) {
234         errorString = ASCIILiteral("Could not find a bound layer for the provided id");
235         return;
236     }
237
238     CompositingReasons reasonsBitmask = renderLayer->compositor().reasonsForCompositing(*renderLayer);
239     auto compositingReasons = Inspector::Protocol::LayerTree::CompositingReasons::create().release();
240
241     if (reasonsBitmask & CompositingReason3DTransform)
242         compositingReasons->setTransform3D(true);
243
244     if (reasonsBitmask & CompositingReasonVideo)
245         compositingReasons->setVideo(true);
246     else if (reasonsBitmask & CompositingReasonCanvas)
247         compositingReasons->setCanvas(true);
248     else if (reasonsBitmask & CompositingReasonPlugin)
249         compositingReasons->setPlugin(true);
250     else if (reasonsBitmask & CompositingReasonIFrame)
251         compositingReasons->setIFrame(true);
252     
253     if (reasonsBitmask & CompositingReasonBackfaceVisibilityHidden)
254         compositingReasons->setBackfaceVisibilityHidden(true);
255
256     if (reasonsBitmask & CompositingReasonClipsCompositingDescendants)
257         compositingReasons->setClipsCompositingDescendants(true);
258
259     if (reasonsBitmask & CompositingReasonAnimation)
260         compositingReasons->setAnimation(true);
261
262     if (reasonsBitmask & CompositingReasonFilters)
263         compositingReasons->setFilters(true);
264
265     if (reasonsBitmask & CompositingReasonPositionFixed)
266         compositingReasons->setPositionFixed(true);
267
268     if (reasonsBitmask & CompositingReasonPositionSticky)
269         compositingReasons->setPositionSticky(true);
270
271     if (reasonsBitmask & CompositingReasonOverflowScrollingTouch)
272         compositingReasons->setOverflowScrollingTouch(true);
273
274     if (reasonsBitmask & CompositingReasonStacking)
275         compositingReasons->setStacking(true);
276
277     if (reasonsBitmask & CompositingReasonOverlap)
278         compositingReasons->setOverlap(true);
279
280     if (reasonsBitmask & CompositingReasonNegativeZIndexChildren)
281         compositingReasons->setNegativeZIndexChildren(true);
282
283     if (reasonsBitmask & CompositingReasonTransformWithCompositedDescendants)
284         compositingReasons->setTransformWithCompositedDescendants(true);
285
286     if (reasonsBitmask & CompositingReasonOpacityWithCompositedDescendants)
287         compositingReasons->setOpacityWithCompositedDescendants(true);
288
289     if (reasonsBitmask & CompositingReasonMaskWithCompositedDescendants)
290         compositingReasons->setMaskWithCompositedDescendants(true);
291
292     if (reasonsBitmask & CompositingReasonReflectionWithCompositedDescendants)
293         compositingReasons->setReflectionWithCompositedDescendants(true);
294
295     if (reasonsBitmask & CompositingReasonFilterWithCompositedDescendants)
296         compositingReasons->setFilterWithCompositedDescendants(true);
297
298     if (reasonsBitmask & CompositingReasonBlendingWithCompositedDescendants)
299         compositingReasons->setBlendingWithCompositedDescendants(true);
300
301     if (reasonsBitmask & CompositingReasonIsolatesCompositedBlendingDescendants)
302         compositingReasons->setIsolatesCompositedBlendingDescendants(true);
303
304     if (reasonsBitmask & CompositingReasonPerspective)
305         compositingReasons->setPerspective(true);
306
307     if (reasonsBitmask & CompositingReasonPreserve3D)
308         compositingReasons->setPreserve3D(true);
309
310     if (reasonsBitmask & CompositingReasonRoot)
311         compositingReasons->setRoot(true);
312     
313     compositingReasonsResult = WTF::move(compositingReasons);
314 }
315
316 String InspectorLayerTreeAgent::bind(const RenderLayer* layer)
317 {
318     if (!layer)
319         return emptyString();
320     String identifier = m_documentLayerToIdMap.get(layer);
321     if (identifier.isNull()) {
322         identifier = IdentifiersFactory::createIdentifier();
323         m_documentLayerToIdMap.set(layer, identifier);
324         m_idToLayer.set(identifier, layer);
325     }
326     return identifier;
327 }
328
329 void InspectorLayerTreeAgent::unbind(const RenderLayer* layer)
330 {
331     HashMap<const RenderLayer*, String>::iterator iterator = m_documentLayerToIdMap.find(layer);
332     if (iterator == m_documentLayerToIdMap.end())
333         return;
334     m_idToLayer.remove(iterator->value);
335     m_documentLayerToIdMap.remove(iterator);
336 }
337
338 String InspectorLayerTreeAgent::bindPseudoElement(PseudoElement* pseudoElement)
339 {
340     if (!pseudoElement)
341         return emptyString();
342     String identifier = m_pseudoElementToIdMap.get(pseudoElement);
343     if (identifier.isNull()) {
344         identifier = IdentifiersFactory::createIdentifier();
345         m_pseudoElementToIdMap.set(pseudoElement, identifier);
346         m_idToPseudoElement.set(identifier, pseudoElement);
347     }
348     return identifier;
349 }
350
351 void InspectorLayerTreeAgent::unbindPseudoElement(PseudoElement* pseudoElement)
352 {
353     HashMap<PseudoElement*, String>::iterator iterator = m_pseudoElementToIdMap.find(pseudoElement);
354     if (iterator == m_pseudoElementToIdMap.end())
355         return;
356     m_idToPseudoElement.remove(iterator->value);
357     m_pseudoElementToIdMap.remove(iterator);
358 }
359
360 } // namespace WebCore