• 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/frame/LocalFrame.h"
37 #include "core/inspector/IdentifiersFactory.h"
38 #include "core/inspector/InspectorNodeIds.h"
39 #include "core/inspector/InspectorState.h"
40 #include "core/inspector/InstrumentingAgents.h"
41 #include "core/loader/DocumentLoader.h"
42 #include "core/page/Page.h"
43 #include "core/rendering/RenderView.h"
44 #include "core/rendering/compositing/CompositedLayerMapping.h"
45 #include "core/rendering/compositing/RenderLayerCompositor.h"
46 #include "platform/geometry/IntRect.h"
47 #include "platform/graphics/CompositingReasons.h"
48 #include "platform/graphics/GraphicsContextRecorder.h"
49 #include "platform/transforms/TransformationMatrix.h"
50 #include "public/platform/WebFloatPoint.h"
51 #include "public/platform/WebLayer.h"
52 #include "wtf/text/Base64.h"
53 
54 namespace WebCore {
55 
56 unsigned InspectorLayerTreeAgent::s_lastSnapshotId;
57 
idForLayer(const GraphicsLayer * graphicsLayer)58 inline String idForLayer(const GraphicsLayer* graphicsLayer)
59 {
60     return String::number(graphicsLayer->platformLayer()->id());
61 }
62 
buildScrollRect(const blink::WebRect & rect,const TypeBuilder::LayerTree::ScrollRect::Type::Enum & type)63 static PassRefPtr<TypeBuilder::LayerTree::ScrollRect> buildScrollRect(const blink::WebRect& rect, const TypeBuilder::LayerTree::ScrollRect::Type::Enum& type)
64 {
65     RefPtr<TypeBuilder::DOM::Rect> rectObject = TypeBuilder::DOM::Rect::create()
66         .setX(rect.x)
67         .setY(rect.y)
68         .setHeight(rect.height)
69         .setWidth(rect.width);
70     RefPtr<TypeBuilder::LayerTree::ScrollRect> scrollRectObject = TypeBuilder::LayerTree::ScrollRect::create()
71         .setRect(rectObject.release())
72         .setType(type);
73     return scrollRectObject.release();
74 }
75 
buildScrollRectsForLayer(GraphicsLayer * graphicsLayer)76 static PassRefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::ScrollRect> > buildScrollRectsForLayer(GraphicsLayer* graphicsLayer)
77 {
78     RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::ScrollRect> > scrollRects = TypeBuilder::Array<TypeBuilder::LayerTree::ScrollRect>::create();
79     blink::WebLayer* webLayer = graphicsLayer->platformLayer();
80     for (size_t i = 0; i < webLayer->nonFastScrollableRegion().size(); ++i) {
81         scrollRects->addItem(buildScrollRect(webLayer->nonFastScrollableRegion()[i], TypeBuilder::LayerTree::ScrollRect::Type::RepaintsOnScroll));
82     }
83     for (size_t i = 0; i < webLayer->touchEventHandlerRegion().size(); ++i) {
84         scrollRects->addItem(buildScrollRect(webLayer->touchEventHandlerRegion()[i], TypeBuilder::LayerTree::ScrollRect::Type::TouchEventHandler));
85     }
86     if (webLayer->haveWheelEventHandlers()) {
87         blink::WebRect webRect(webLayer->position().x, webLayer->position().y, webLayer->bounds().width, webLayer->bounds().height);
88         scrollRects->addItem(buildScrollRect(webRect, TypeBuilder::LayerTree::ScrollRect::Type::WheelEventHandler));
89     }
90     return scrollRects->length() ? scrollRects.release() : nullptr;
91 }
92 
buildObjectForLayer(GraphicsLayer * graphicsLayer,int nodeId)93 static PassRefPtr<TypeBuilder::LayerTree::Layer> buildObjectForLayer(GraphicsLayer* graphicsLayer, int nodeId)
94 {
95     blink::WebLayer* webLayer = graphicsLayer->platformLayer();
96     RefPtr<TypeBuilder::LayerTree::Layer> layerObject = TypeBuilder::LayerTree::Layer::create()
97         .setLayerId(idForLayer(graphicsLayer))
98         .setOffsetX(webLayer->position().x)
99         .setOffsetY(webLayer->position().y)
100         .setWidth(webLayer->bounds().width)
101         .setHeight(webLayer->bounds().height)
102         .setPaintCount(graphicsLayer->paintCount());
103 
104     if (nodeId)
105         layerObject->setBackendNodeId(nodeId);
106 
107     GraphicsLayer* parent = graphicsLayer->parent();
108     if (!parent)
109         parent = graphicsLayer->replicatedLayer();
110     if (parent)
111         layerObject->setParentLayerId(idForLayer(parent));
112     if (!graphicsLayer->contentsAreVisible())
113         layerObject->setInvisible(true);
114     const TransformationMatrix& transform = graphicsLayer->transform();
115     if (!transform.isIdentity()) {
116         TransformationMatrix::FloatMatrix4 flattenedMatrix;
117         transform.toColumnMajorFloatArray(flattenedMatrix);
118         RefPtr<TypeBuilder::Array<double> > transformArray = TypeBuilder::Array<double>::create();
119         for (size_t i = 0; i < WTF_ARRAY_LENGTH(flattenedMatrix); ++i)
120             transformArray->addItem(flattenedMatrix[i]);
121         layerObject->setTransform(transformArray);
122         const FloatPoint3D& transformOrigin = graphicsLayer->transformOrigin();
123         // FIXME: rename these to setTransformOrigin*
124         if (webLayer->bounds().width > 0)
125             layerObject->setAnchorX(transformOrigin.x() / webLayer->bounds().width);
126         else
127             layerObject->setAnchorX(0.0);
128         if (webLayer->bounds().height > 0)
129             layerObject->setAnchorY(transformOrigin.y() / webLayer->bounds().height);
130         else
131             layerObject->setAnchorY(0.0);
132         layerObject->setAnchorZ(transformOrigin.z());
133     }
134     RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::ScrollRect> > scrollRects = buildScrollRectsForLayer(graphicsLayer);
135     if (scrollRects)
136         layerObject->setScrollRects(scrollRects.release());
137     return layerObject;
138 }
139 
InspectorLayerTreeAgent(Page * page)140 InspectorLayerTreeAgent::InspectorLayerTreeAgent(Page* page)
141     : InspectorBaseAgent<InspectorLayerTreeAgent>("LayerTree")
142     , m_frontend(0)
143     , m_page(page)
144 {
145 }
146 
~InspectorLayerTreeAgent()147 InspectorLayerTreeAgent::~InspectorLayerTreeAgent()
148 {
149 }
150 
setFrontend(InspectorFrontend * frontend)151 void InspectorLayerTreeAgent::setFrontend(InspectorFrontend* frontend)
152 {
153     m_frontend = frontend->layertree();
154 }
155 
clearFrontend()156 void InspectorLayerTreeAgent::clearFrontend()
157 {
158     m_frontend = 0;
159     disable(0);
160 }
161 
restore()162 void InspectorLayerTreeAgent::restore()
163 {
164     // We do not re-enable layer agent automatically after navigation. This is because
165     // it depends on DOMAgent and node ids in particular, so we let front-end request document
166     // and re-enable the agent manually after this.
167 }
168 
enable(ErrorString *)169 void InspectorLayerTreeAgent::enable(ErrorString*)
170 {
171     m_instrumentingAgents->setInspectorLayerTreeAgent(this);
172     if (LocalFrame* frame = m_page->deprecatedLocalMainFrame()) {
173         Document* document = frame->document();
174         if (document && document->lifecycle().state() >= DocumentLifecycle::CompositingClean)
175             layerTreeDidChange();
176     }
177 }
178 
disable(ErrorString *)179 void InspectorLayerTreeAgent::disable(ErrorString*)
180 {
181     m_instrumentingAgents->setInspectorLayerTreeAgent(0);
182     m_snapshotById.clear();
183     ErrorString unused;
184 }
185 
layerTreeDidChange()186 void InspectorLayerTreeAgent::layerTreeDidChange()
187 {
188     m_frontend->layerTreeDidChange(buildLayerTree());
189 }
190 
didPaint(RenderObject *,const GraphicsLayer * graphicsLayer,GraphicsContext *,const LayoutRect & rect)191 void InspectorLayerTreeAgent::didPaint(RenderObject*, const GraphicsLayer* graphicsLayer, GraphicsContext*, const LayoutRect& rect)
192 {
193     // Should only happen for FrameView paints when compositing is off. Consider different instrumentation method for that.
194     if (!graphicsLayer)
195         return;
196 
197     RefPtr<TypeBuilder::DOM::Rect> domRect = TypeBuilder::DOM::Rect::create()
198         .setX(rect.x())
199         .setY(rect.y())
200         .setWidth(rect.width())
201         .setHeight(rect.height());
202     m_frontend->layerPainted(idForLayer(graphicsLayer), domRect.release());
203 }
204 
buildLayerTree()205 PassRefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> > InspectorLayerTreeAgent::buildLayerTree()
206 {
207     RenderLayerCompositor* compositor = renderLayerCompositor();
208     if (!compositor || !compositor->inCompositingMode())
209         return nullptr;
210 
211     LayerIdToNodeIdMap layerIdToNodeIdMap;
212     RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> > layers = TypeBuilder::Array<TypeBuilder::LayerTree::Layer>::create();
213     buildLayerIdToNodeIdMap(compositor->rootRenderLayer(), layerIdToNodeIdMap);
214     gatherGraphicsLayers(compositor->rootGraphicsLayer(), layerIdToNodeIdMap, layers);
215     return layers.release();
216 }
217 
buildLayerIdToNodeIdMap(RenderLayer * root,LayerIdToNodeIdMap & layerIdToNodeIdMap)218 void InspectorLayerTreeAgent::buildLayerIdToNodeIdMap(RenderLayer* root, LayerIdToNodeIdMap& layerIdToNodeIdMap)
219 {
220     if (root->hasCompositedLayerMapping()) {
221         if (Node* node = root->renderer()->generatingNode()) {
222             GraphicsLayer* graphicsLayer = root->compositedLayerMapping()->childForSuperlayers();
223             layerIdToNodeIdMap.set(graphicsLayer->platformLayer()->id(), idForNode(node));
224         }
225     }
226     for (RenderLayer* child = root->firstChild(); child; child = child->nextSibling())
227         buildLayerIdToNodeIdMap(child, layerIdToNodeIdMap);
228     if (!root->renderer()->isRenderIFrame())
229         return;
230     FrameView* childFrameView = toFrameView(toRenderWidget(root->renderer())->widget());
231     if (RenderView* childRenderView = childFrameView->renderView()) {
232         if (RenderLayerCompositor* childCompositor = childRenderView->compositor())
233             buildLayerIdToNodeIdMap(childCompositor->rootRenderLayer(), layerIdToNodeIdMap);
234     }
235 }
236 
gatherGraphicsLayers(GraphicsLayer * root,HashMap<int,int> & layerIdToNodeIdMap,RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer>> & layers)237 void InspectorLayerTreeAgent::gatherGraphicsLayers(GraphicsLayer* root, HashMap<int, int>& layerIdToNodeIdMap, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
238 {
239     int layerId = root->platformLayer()->id();
240     if (m_pageOverlayLayerIds.find(layerId) != WTF::kNotFound)
241         return;
242     layers->addItem(buildObjectForLayer(root, layerIdToNodeIdMap.get(layerId)));
243     if (GraphicsLayer* replica = root->replicaLayer())
244         gatherGraphicsLayers(replica, layerIdToNodeIdMap, layers);
245     for (size_t i = 0, size = root->children().size(); i < size; ++i)
246         gatherGraphicsLayers(root->children()[i], layerIdToNodeIdMap, layers);
247 }
248 
idForNode(Node * node)249 int InspectorLayerTreeAgent::idForNode(Node* node)
250 {
251     return InspectorNodeIds::idForNode(node);
252 }
253 
renderLayerCompositor()254 RenderLayerCompositor* InspectorLayerTreeAgent::renderLayerCompositor()
255 {
256     RenderView* renderView = m_page->deprecatedLocalMainFrame()->contentRenderer();
257     RenderLayerCompositor* compositor = renderView ? renderView->compositor() : 0;
258     return compositor;
259 }
260 
findLayerById(GraphicsLayer * root,int layerId)261 static GraphicsLayer* findLayerById(GraphicsLayer* root, int layerId)
262 {
263     if (root->platformLayer()->id() == layerId)
264         return root;
265     if (root->replicaLayer()) {
266         if (GraphicsLayer* layer = findLayerById(root->replicaLayer(), layerId))
267             return layer;
268     }
269     for (size_t i = 0, size = root->children().size(); i < size; ++i) {
270         if (GraphicsLayer* layer = findLayerById(root->children()[i], layerId))
271             return layer;
272     }
273     return 0;
274 }
275 
layerById(ErrorString * errorString,const String & layerId)276 GraphicsLayer* InspectorLayerTreeAgent::layerById(ErrorString* errorString, const String& layerId)
277 {
278     bool ok;
279     int id = layerId.toInt(&ok);
280     if (!ok) {
281         *errorString = "Invalid layer id";
282         return 0;
283     }
284     RenderLayerCompositor* compositor = renderLayerCompositor();
285     if (!compositor) {
286         *errorString = "Not in compositing mode";
287         return 0;
288     }
289 
290     GraphicsLayer* result = findLayerById(compositor->rootGraphicsLayer(), id);
291     if (!result)
292         *errorString = "No layer matching given id found";
293     return result;
294 }
295 
compositingReasons(ErrorString * errorString,const String & layerId,RefPtr<TypeBuilder::Array<String>> & reasonStrings)296 void InspectorLayerTreeAgent::compositingReasons(ErrorString* errorString, const String& layerId, RefPtr<TypeBuilder::Array<String> >& reasonStrings)
297 {
298     const GraphicsLayer* graphicsLayer = layerById(errorString, layerId);
299     if (!graphicsLayer)
300         return;
301     CompositingReasons reasonsBitmask = graphicsLayer->compositingReasons();
302     reasonStrings = TypeBuilder::Array<String>::create();
303     for (size_t i = 0; i < WTF_ARRAY_LENGTH(compositingReasonStringMap); ++i) {
304         if (!(reasonsBitmask & compositingReasonStringMap[i].reason))
305             continue;
306         reasonStrings->addItem(compositingReasonStringMap[i].shortName);
307 #ifndef _NDEBUG
308         reasonsBitmask &= ~compositingReasonStringMap[i].reason;
309 #endif
310     }
311     ASSERT(!reasonsBitmask);
312 }
313 
makeSnapshot(ErrorString * errorString,const String & layerId,String * snapshotId)314 void InspectorLayerTreeAgent::makeSnapshot(ErrorString* errorString, const String& layerId, String* snapshotId)
315 {
316     GraphicsLayer* layer = layerById(errorString, layerId);
317     if (!layer)
318         return;
319 
320     GraphicsContextRecorder recorder;
321     IntSize size = expandedIntSize(layer->size());
322     GraphicsContext* context = recorder.record(size, layer->contentsOpaque());
323     layer->paint(*context, IntRect(IntPoint(0, 0), size));
324     RefPtr<GraphicsContextSnapshot> snapshot = recorder.stop();
325     *snapshotId = String::number(++s_lastSnapshotId);
326     bool newEntry = m_snapshotById.add(*snapshotId, snapshot).isNewEntry;
327     ASSERT_UNUSED(newEntry, newEntry);
328 }
329 
loadSnapshot(ErrorString * errorString,const String & data,String * snapshotId)330 void InspectorLayerTreeAgent::loadSnapshot(ErrorString* errorString, const String& data, String* snapshotId)
331 {
332     Vector<char> snapshotData;
333     if (!base64Decode(data, snapshotData)) {
334         *errorString = "Invalid base64 encoding";
335         return;
336     }
337     RefPtr<GraphicsContextSnapshot> snapshot = GraphicsContextSnapshot::load(snapshotData.data(), snapshotData.size());
338     if (!snapshot) {
339         *errorString = "Invalida snapshot format";
340         return;
341     }
342     *snapshotId = String::number(++s_lastSnapshotId);
343     bool newEntry = m_snapshotById.add(*snapshotId, snapshot).isNewEntry;
344     ASSERT_UNUSED(newEntry, newEntry);
345 }
346 
releaseSnapshot(ErrorString * errorString,const String & snapshotId)347 void InspectorLayerTreeAgent::releaseSnapshot(ErrorString* errorString, const String& snapshotId)
348 {
349     SnapshotById::iterator it = m_snapshotById.find(snapshotId);
350     if (it == m_snapshotById.end()) {
351         *errorString = "Snapshot not found";
352         return;
353     }
354     m_snapshotById.remove(it);
355 }
356 
snapshotById(ErrorString * errorString,const String & snapshotId)357 const GraphicsContextSnapshot* InspectorLayerTreeAgent::snapshotById(ErrorString* errorString, const String& snapshotId)
358 {
359     SnapshotById::iterator it = m_snapshotById.find(snapshotId);
360     if (it == m_snapshotById.end()) {
361         *errorString = "Snapshot not found";
362         return 0;
363     }
364     return it->value.get();
365 }
366 
replaySnapshot(ErrorString * errorString,const String & snapshotId,const int * fromStep,const int * toStep,String * dataURL)367 void InspectorLayerTreeAgent::replaySnapshot(ErrorString* errorString, const String& snapshotId, const int* fromStep, const int* toStep, String* dataURL)
368 {
369     const GraphicsContextSnapshot* snapshot = snapshotById(errorString, snapshotId);
370     if (!snapshot)
371         return;
372     OwnPtr<ImageBuffer> imageBuffer = snapshot->replay(fromStep ? *fromStep : 0, toStep ? *toStep : 0);
373     *dataURL = imageBuffer->toDataURL("image/png");
374 }
375 
profileSnapshot(ErrorString * errorString,const String & snapshotId,const int * minRepeatCount,const double * minDuration,RefPtr<TypeBuilder::Array<TypeBuilder::Array<double>>> & outTimings)376 void InspectorLayerTreeAgent::profileSnapshot(ErrorString* errorString, const String& snapshotId, const int* minRepeatCount, const double* minDuration, RefPtr<TypeBuilder::Array<TypeBuilder::Array<double> > >& outTimings)
377 {
378     const GraphicsContextSnapshot* snapshot = snapshotById(errorString, snapshotId);
379     if (!snapshot)
380         return;
381     OwnPtr<GraphicsContextSnapshot::Timings> timings = snapshot->profile(minRepeatCount ? *minRepeatCount : 1, minDuration ? *minDuration : 0);
382     outTimings = TypeBuilder::Array<TypeBuilder::Array<double> >::create();
383     for (size_t i = 0; i < timings->size(); ++i) {
384         const Vector<double>& row = (*timings)[i];
385         RefPtr<TypeBuilder::Array<double> > outRow = TypeBuilder::Array<double>::create();
386         for (size_t j = 1; j < row.size(); ++j)
387             outRow->addItem(row[j] - row[j - 1]);
388         outTimings->addItem(outRow.release());
389     }
390 }
391 
snapshotCommandLog(ErrorString * errorString,const String & snapshotId,RefPtr<TypeBuilder::Array<JSONObject>> & commandLog)392 void InspectorLayerTreeAgent::snapshotCommandLog(ErrorString* errorString, const String& snapshotId, RefPtr<TypeBuilder::Array<JSONObject> >& commandLog)
393 {
394     const GraphicsContextSnapshot* snapshot = snapshotById(errorString, snapshotId);
395     if (!snapshot)
396         return;
397     commandLog = TypeBuilder::Array<JSONObject>::runtimeCast(snapshot->snapshotCommandLog());
398 }
399 
willAddPageOverlay(const GraphicsLayer * layer)400 void InspectorLayerTreeAgent::willAddPageOverlay(const GraphicsLayer* layer)
401 {
402     m_pageOverlayLayerIds.append(layer->platformLayer()->id());
403 }
404 
didRemovePageOverlay(const GraphicsLayer * layer)405 void InspectorLayerTreeAgent::didRemovePageOverlay(const GraphicsLayer* layer)
406 {
407     size_t index = m_pageOverlayLayerIds.find(layer->platformLayer()->id());
408     if (index == WTF::kNotFound)
409         return;
410     m_pageOverlayLayerIds.remove(index);
411 }
412 
413 
414 } // namespace WebCore
415