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