• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
3  * Copyright (C) 2013 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "config.h"
33 
34 #include "core/inspector/InspectorLayerTreeAgent.h"
35 
36 #include "core/inspector/IdentifiersFactory.h"
37 #include "core/inspector/InspectorDOMAgent.h"
38 #include "core/inspector/InspectorState.h"
39 #include "core/inspector/InstrumentingAgents.h"
40 #include "core/loader/DocumentLoader.h"
41 #include "core/frame/Frame.h"
42 #include "core/page/Page.h"
43 #include "core/rendering/CompositedLayerMapping.h"
44 #include "core/rendering/RenderLayerCompositor.h"
45 #include "core/rendering/RenderView.h"
46 #include "platform/geometry/IntRect.h"
47 #include "platform/graphics/GraphicsContextRecorder.h"
48 #include "platform/transforms/TransformationMatrix.h"
49 #include "public/platform/WebCompositingReasons.h"
50 #include "public/platform/WebLayer.h"
51 
52 namespace WebCore {
53 
54 unsigned InspectorLayerTreeAgent::s_lastSnapshotId;
55 
56 struct LayerSnapshot {
LayerSnapshotWebCore::LayerSnapshot57     LayerSnapshot()
58         : layerId(0)
59     {
60     }
LayerSnapshotWebCore::LayerSnapshot61     LayerSnapshot(int layerId, PassRefPtr<GraphicsContextSnapshot> graphicsSnapshot)
62         : layerId(layerId)
63         , graphicsSnapshot(graphicsSnapshot)
64     {
65     }
66     int layerId;
67     RefPtr<GraphicsContextSnapshot> graphicsSnapshot;
68 };
69 
idForLayer(const GraphicsLayer * graphicsLayer)70 inline String idForLayer(const GraphicsLayer* graphicsLayer)
71 {
72     return String::number(graphicsLayer->platformLayer()->id());
73 }
74 
buildObjectForLayer(GraphicsLayer * graphicsLayer,int nodeId)75 static PassRefPtr<TypeBuilder::LayerTree::Layer> buildObjectForLayer(GraphicsLayer* graphicsLayer, int nodeId)
76 {
77     RefPtr<TypeBuilder::LayerTree::Layer> layerObject = TypeBuilder::LayerTree::Layer::create()
78         .setLayerId(idForLayer(graphicsLayer))
79         .setOffsetX(graphicsLayer->position().x())
80         .setOffsetY(graphicsLayer->position().y())
81         .setWidth(graphicsLayer->size().width())
82         .setHeight(graphicsLayer->size().height())
83         .setPaintCount(graphicsLayer->paintCount());
84 
85     if (nodeId)
86         layerObject->setNodeId(nodeId);
87 
88     GraphicsLayer* parent = graphicsLayer->parent();
89     if (!parent)
90         parent = graphicsLayer->replicatedLayer();
91     if (parent)
92         layerObject->setParentLayerId(idForLayer(parent));
93     if (!graphicsLayer->contentsAreVisible())
94         layerObject->setInvisible(true);
95     const TransformationMatrix& transform = graphicsLayer->transform();
96     if (!transform.isIdentity()) {
97         TransformationMatrix::FloatMatrix4 flattenedMatrix;
98         transform.toColumnMajorFloatArray(flattenedMatrix);
99         RefPtr<TypeBuilder::Array<double> > transformArray = TypeBuilder::Array<double>::create();
100         for (size_t i = 0; i < WTF_ARRAY_LENGTH(flattenedMatrix); ++i)
101             transformArray->addItem(flattenedMatrix[i]);
102         layerObject->setTransform(transformArray);
103         const FloatPoint3D& anchor = graphicsLayer->anchorPoint();
104         layerObject->setAnchorX(anchor.x());
105         layerObject->setAnchorY(anchor.y());
106         layerObject->setAnchorZ(anchor.z());
107     }
108     return layerObject;
109 }
110 
gatherGraphicsLayers(GraphicsLayer * root,HashMap<int,int> & layerIdToNodeIdMap,RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer>> & layers)111 void gatherGraphicsLayers(GraphicsLayer* root, HashMap<int, int>& layerIdToNodeIdMap, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
112 {
113     int layerId = root->platformLayer()->id();
114     layers->addItem(buildObjectForLayer(root, layerIdToNodeIdMap.get(layerId)));
115     if (GraphicsLayer* replica = root->replicaLayer())
116         gatherGraphicsLayers(replica, layerIdToNodeIdMap, layers);
117     for (size_t i = 0, size = root->children().size(); i < size; ++i)
118         gatherGraphicsLayers(root->children()[i], layerIdToNodeIdMap, layers);
119 }
120 
InspectorLayerTreeAgent(InstrumentingAgents * instrumentingAgents,InspectorCompositeState * state,InspectorDOMAgent * domAgent,Page * page)121 InspectorLayerTreeAgent::InspectorLayerTreeAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorDOMAgent* domAgent, Page* page)
122     : InspectorBaseAgent<InspectorLayerTreeAgent>("LayerTree", instrumentingAgents, state)
123     , m_frontend(0)
124     , m_page(page)
125     , m_domAgent(domAgent)
126 {
127 }
128 
~InspectorLayerTreeAgent()129 InspectorLayerTreeAgent::~InspectorLayerTreeAgent()
130 {
131 }
132 
setFrontend(InspectorFrontend * frontend)133 void InspectorLayerTreeAgent::setFrontend(InspectorFrontend* frontend)
134 {
135     m_frontend = frontend->layertree();
136 }
137 
clearFrontend()138 void InspectorLayerTreeAgent::clearFrontend()
139 {
140     m_frontend = 0;
141     disable(0);
142 }
143 
restore()144 void InspectorLayerTreeAgent::restore()
145 {
146     // We do not re-enable layer agent automatically after navigation. This is because
147     // it depends on DOMAgent and node ids in particular, so we let front-end request document
148     // and re-enable the agent manually after this.
149 }
150 
enable(ErrorString *)151 void InspectorLayerTreeAgent::enable(ErrorString*)
152 {
153     m_instrumentingAgents->setInspectorLayerTreeAgent(this);
154     layerTreeDidChange();
155 }
156 
disable(ErrorString *)157 void InspectorLayerTreeAgent::disable(ErrorString*)
158 {
159     m_instrumentingAgents->setInspectorLayerTreeAgent(0);
160     m_snapshotById.clear();
161 }
162 
layerTreeDidChange()163 void InspectorLayerTreeAgent::layerTreeDidChange()
164 {
165     m_frontend->layerTreeDidChange(buildLayerTree());
166 }
167 
didPaint(RenderObject *,const GraphicsLayer * graphicsLayer,GraphicsContext *,const LayoutRect & rect)168 void InspectorLayerTreeAgent::didPaint(RenderObject*, const GraphicsLayer* graphicsLayer, GraphicsContext*, const LayoutRect& rect)
169 {
170     // Should only happen for FrameView paints when compositing is off. Consider different instrumentation method for that.
171     if (!graphicsLayer)
172         return;
173 
174     RefPtr<TypeBuilder::DOM::Rect> domRect = TypeBuilder::DOM::Rect::create()
175         .setX(rect.x())
176         .setY(rect.y())
177         .setWidth(rect.width())
178         .setHeight(rect.height());
179     m_frontend->layerPainted(idForLayer(graphicsLayer), domRect.release());
180 }
181 
buildLayerTree()182 PassRefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> > InspectorLayerTreeAgent::buildLayerTree()
183 {
184     RenderLayerCompositor* compositor = renderLayerCompositor();
185     if (!compositor || !compositor->inCompositingMode())
186         return 0;
187     LayerIdToNodeIdMap layerIdToNodeIdMap;
188     RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> > layers = TypeBuilder::Array<TypeBuilder::LayerTree::Layer>::create();
189     buildLayerIdToNodeIdMap(compositor->rootRenderLayer(), layerIdToNodeIdMap);
190     gatherGraphicsLayers(compositor->rootGraphicsLayer(), layerIdToNodeIdMap, layers);
191     return layers.release();
192 }
193 
buildLayerIdToNodeIdMap(RenderLayer * root,LayerIdToNodeIdMap & layerIdToNodeIdMap)194 void InspectorLayerTreeAgent::buildLayerIdToNodeIdMap(RenderLayer* root, LayerIdToNodeIdMap& layerIdToNodeIdMap)
195 {
196     if (root->hasCompositedLayerMapping()) {
197         if (Node* node = root->renderer()->generatingNode()) {
198             GraphicsLayer* graphicsLayer = root->compositedLayerMapping()->childForSuperlayers();
199             layerIdToNodeIdMap.set(graphicsLayer->platformLayer()->id(), idForNode(node));
200         }
201     }
202     for (RenderLayer* child = root->firstChild(); child; child = child->nextSibling())
203         buildLayerIdToNodeIdMap(child, layerIdToNodeIdMap);
204     if (!root->renderer()->isRenderIFrame())
205         return;
206     FrameView* childFrameView = toFrameView(toRenderWidget(root->renderer())->widget());
207     if (RenderView* childRenderView = childFrameView->renderView()) {
208         if (RenderLayerCompositor* childCompositor = childRenderView->compositor())
209             buildLayerIdToNodeIdMap(childCompositor->rootRenderLayer(), layerIdToNodeIdMap);
210     }
211 }
212 
idForNode(Node * node)213 int InspectorLayerTreeAgent::idForNode(Node* node)
214 {
215     int nodeId = m_domAgent->boundNodeId(node);
216     if (!nodeId) {
217         ErrorString ignoredError;
218         nodeId = m_domAgent->pushNodeToFrontend(&ignoredError, m_domAgent->boundNodeId(&node->document()), node);
219     }
220     return nodeId;
221 }
222 
renderLayerCompositor()223 RenderLayerCompositor* InspectorLayerTreeAgent::renderLayerCompositor()
224 {
225     RenderView* renderView = m_page->mainFrame()->contentRenderer();
226     RenderLayerCompositor* compositor = renderView ? renderView->compositor() : 0;
227     return compositor;
228 }
229 
findLayerById(GraphicsLayer * root,int layerId)230 static GraphicsLayer* findLayerById(GraphicsLayer* root, int layerId)
231 {
232     if (root->platformLayer()->id() == layerId)
233         return root;
234     if (root->replicaLayer()) {
235         if (GraphicsLayer* layer = findLayerById(root->replicaLayer(), layerId))
236             return layer;
237     }
238     for (size_t i = 0, size = root->children().size(); i < size; ++i) {
239         if (GraphicsLayer* layer = findLayerById(root->children()[i], layerId))
240             return layer;
241     }
242     return 0;
243 }
244 
layerById(ErrorString * errorString,const String & layerId)245 GraphicsLayer* InspectorLayerTreeAgent::layerById(ErrorString* errorString, const String& layerId)
246 {
247     bool ok;
248     int id = layerId.toInt(&ok);
249     if (!ok) {
250         *errorString = "Invalid layer id";
251         return 0;
252     }
253     RenderLayerCompositor* compositor = renderLayerCompositor();
254     if (!compositor) {
255         *errorString = "Not in compositing mode";
256         return 0;
257     }
258 
259     GraphicsLayer* result = findLayerById(compositor->rootGraphicsLayer(), id);
260     if (!result)
261         *errorString = "No layer matching given id found";
262     return result;
263 }
264 
265 struct CompositingReasonToProtocolName {
266     uint64_t mask;
267     const char *protocolName;
268 };
269 
270 
compositingReasons(ErrorString * errorString,const String & layerId,RefPtr<TypeBuilder::Array<String>> & reasonStrings)271 void InspectorLayerTreeAgent::compositingReasons(ErrorString* errorString, const String& layerId, RefPtr<TypeBuilder::Array<String> >& reasonStrings)
272 {
273     static CompositingReasonToProtocolName compositingReasonNames[] = {
274         { CompositingReason3DTransform, "transform3D" },
275         { CompositingReasonVideo, "video" },
276         { CompositingReasonCanvas, "canvas" },
277         { CompositingReasonPlugin, "plugin" },
278         { CompositingReasonIFrame, "iFrame" },
279         { CompositingReasonBackfaceVisibilityHidden, "backfaceVisibilityHidden" },
280         { CompositingReasonAnimation, "animation" },
281         { CompositingReasonFilters, "filters" },
282         { CompositingReasonPositionFixed, "positionFixed" },
283         { CompositingReasonPositionSticky, "positionSticky" },
284         { CompositingReasonOverflowScrollingTouch, "overflowScrollingTouch" },
285         { CompositingReasonAssumedOverlap, "assumedOverlap" },
286         { CompositingReasonOverlap, "overlap" },
287         { CompositingReasonNegativeZIndexChildren, "negativeZIndexChildren" },
288         { CompositingReasonTransformWithCompositedDescendants, "transformWithCompositedDescendants" },
289         { CompositingReasonOpacityWithCompositedDescendants, "opacityWithCompositedDescendants" },
290         { CompositingReasonMaskWithCompositedDescendants, "maskWithCompositedDescendants" },
291         { CompositingReasonReflectionWithCompositedDescendants, "reflectionWithCompositedDescendants" },
292         { CompositingReasonFilterWithCompositedDescendants, "filterWithCompositedDescendants" },
293         { CompositingReasonBlendingWithCompositedDescendants, "blendingWithCompositedDescendants" },
294         { CompositingReasonClipsCompositingDescendants, "clipsCompositingDescendants" },
295         { CompositingReasonPerspective, "perspective" },
296         { CompositingReasonPreserve3D, "preserve3D" },
297         { CompositingReasonRoot, "root" },
298         { CompositingReasonLayerForClip, "layerForClip" },
299         { CompositingReasonLayerForScrollbar, "layerForScrollbar" },
300         { CompositingReasonLayerForScrollingContainer, "layerForScrollingContainer" },
301         { CompositingReasonLayerForForeground, "layerForForeground" },
302         { CompositingReasonLayerForBackground, "layerForBackground" },
303         { CompositingReasonLayerForMask, "layerForMask" },
304         { CompositingReasonLayerForVideoOverlay, "layerForVideoOverlay" },
305         { CompositingReasonIsolateCompositedDescendants, "isolateCompositedDescendants" }
306     };
307 
308     const GraphicsLayer* graphicsLayer = layerById(errorString, layerId);
309     if (!graphicsLayer)
310         return;
311     blink::WebCompositingReasons reasonsBitmask = graphicsLayer->compositingReasons();
312     reasonStrings = TypeBuilder::Array<String>::create();
313     for (size_t i = 0; i < WTF_ARRAY_LENGTH(compositingReasonNames); ++i) {
314         if (!(reasonsBitmask & compositingReasonNames[i].mask))
315             continue;
316         reasonStrings->addItem(compositingReasonNames[i].protocolName);
317 #ifndef _NDEBUG
318         reasonsBitmask &= ~compositingReasonNames[i].mask;
319 #endif
320     }
321     ASSERT(!reasonsBitmask);
322 }
323 
makeSnapshot(ErrorString * errorString,const String & layerId,String * snapshotId)324 void InspectorLayerTreeAgent::makeSnapshot(ErrorString* errorString, const String& layerId, String* snapshotId)
325 {
326     GraphicsLayer* layer = layerById(errorString, layerId);
327     if (!layer)
328         return;
329 
330     GraphicsContextRecorder recorder;
331     IntSize size = expandedIntSize(layer->size());
332     GraphicsContext* context = recorder.record(size, layer->contentsOpaque());
333     layer->paint(*context, IntRect(IntPoint(0, 0), size));
334     RefPtr<GraphicsContextSnapshot> snapshot = recorder.stop();
335     *snapshotId = String::number(++s_lastSnapshotId);
336     bool newEntry = m_snapshotById.add(*snapshotId, LayerSnapshot(layer->platformLayer()->id(), snapshot)).isNewEntry;
337     ASSERT_UNUSED(newEntry, newEntry);
338 }
339 
releaseSnapshot(ErrorString * errorString,const String & snapshotId)340 void InspectorLayerTreeAgent::releaseSnapshot(ErrorString* errorString, const String& snapshotId)
341 {
342     SnapshotById::iterator it = m_snapshotById.find(snapshotId);
343     if (it == m_snapshotById.end()) {
344         *errorString = "Snapshot not found";
345         return;
346     }
347     m_snapshotById.remove(it);
348 }
349 
snapshotById(ErrorString * errorString,const String & snapshotId)350 const LayerSnapshot* InspectorLayerTreeAgent::snapshotById(ErrorString* errorString, const String& snapshotId)
351 {
352     SnapshotById::iterator it = m_snapshotById.find(snapshotId);
353     if (it == m_snapshotById.end()) {
354         *errorString = "Snapshot not found";
355         return 0;
356     }
357     return &it->value;
358 }
359 
replaySnapshot(ErrorString * errorString,const String & snapshotId,const int * fromStep,const int * toStep,String * dataURL)360 void InspectorLayerTreeAgent::replaySnapshot(ErrorString* errorString, const String& snapshotId, const int* fromStep, const int* toStep, String* dataURL)
361 {
362     const LayerSnapshot* snapshot = snapshotById(errorString, snapshotId);
363     if (!snapshot)
364         return;
365     OwnPtr<ImageBuffer> imageBuffer = snapshot->graphicsSnapshot->replay(fromStep ? *fromStep : 0, toStep ? *toStep : 0);
366     *dataURL = imageBuffer->toDataURL("image/png");
367 }
368 
profileSnapshot(ErrorString * errorString,const String & snapshotId,const int * minRepeatCount,const double * minDuration,RefPtr<TypeBuilder::Array<TypeBuilder::Array<double>>> & outTimings)369 void InspectorLayerTreeAgent::profileSnapshot(ErrorString* errorString, const String& snapshotId, const int* minRepeatCount, const double* minDuration, RefPtr<TypeBuilder::Array<TypeBuilder::Array<double> > >& outTimings)
370 {
371     const LayerSnapshot* snapshot = snapshotById(errorString, snapshotId);
372     if (!snapshot)
373         return;
374     OwnPtr<GraphicsContextSnapshot::Timings> timings = snapshot->graphicsSnapshot->profile(minRepeatCount ? *minRepeatCount : 1, minDuration ? *minDuration : 0);
375     outTimings = TypeBuilder::Array<TypeBuilder::Array<double> >::create();
376     for (size_t i = 0; i < timings->size(); ++i) {
377         const Vector<double>& row = (*timings)[i];
378         RefPtr<TypeBuilder::Array<double> > outRow = TypeBuilder::Array<double>::create();
379         for (size_t j = 1; j < row.size(); ++j)
380             outRow->addItem(row[j] - row[j - 1]);
381         outTimings->addItem(outRow.release());
382     }
383 }
384 
385 } // namespace WebCore
386