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