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