Home | History | Annotate | Download | only in inspector
      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 
     58 namespace blink {
     59 
     60 unsigned InspectorLayerTreeAgent::s_lastSnapshotId;
     61 
     62 inline String idForLayer(const GraphicsLayer* graphicsLayer)
     63 {
     64     return String::number(graphicsLayer->platformLayer()->id());
     65 }
     66 
     67 static 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 
     80 static 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 
     97 static 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 
    144 InspectorLayerTreeAgent::InspectorLayerTreeAgent(Page* page)
    145     : InspectorBaseAgent<InspectorLayerTreeAgent>("LayerTree")
    146     , m_frontend(0)
    147     , m_page(page)
    148 {
    149 }
    150 
    151 InspectorLayerTreeAgent::~InspectorLayerTreeAgent()
    152 {
    153 }
    154 
    155 void InspectorLayerTreeAgent::trace(Visitor* visitor)
    156 {
    157     visitor->trace(m_page);
    158     InspectorBaseAgent::trace(visitor);
    159 }
    160 
    161 void InspectorLayerTreeAgent::setFrontend(InspectorFrontend* frontend)
    162 {
    163     m_frontend = frontend->layertree();
    164 }
    165 
    166 void InspectorLayerTreeAgent::clearFrontend()
    167 {
    168     m_frontend = 0;
    169     disable(0);
    170 }
    171 
    172 void 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 
    179 void 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 
    189 void InspectorLayerTreeAgent::disable(ErrorString*)
    190 {
    191     m_instrumentingAgents->setInspectorLayerTreeAgent(0);
    192     m_snapshotById.clear();
    193     ErrorString unused;
    194 }
    195 
    196 void InspectorLayerTreeAgent::layerTreeDidChange()
    197 {
    198     m_frontend->layerTreeDidChange(buildLayerTree());
    199 }
    200 
    201 void 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 
    215 PassRefPtr<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 
    228 void 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 
    247 void 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 
    259 int InspectorLayerTreeAgent::idForNode(Node* node)
    260 {
    261     return InspectorNodeIds::idForNode(node);
    262 }
    263 
    264 RenderLayerCompositor* InspectorLayerTreeAgent::renderLayerCompositor()
    265 {
    266     RenderView* renderView = m_page->deprecatedLocalMainFrame()->contentRenderer();
    267     RenderLayerCompositor* compositor = renderView ? renderView->compositor() : 0;
    268     return compositor;
    269 }
    270 
    271 static 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 
    286 GraphicsLayer* 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 
    306 void 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 
    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, snapshot).isNewEntry;
    337     ASSERT_UNUSED(newEntry, newEntry);
    338 }
    339 
    340 void 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 
    357 void 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 
    367 const 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 
    377 void 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 
    394 void 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 
    410 void 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 
    418 void InspectorLayerTreeAgent::willAddPageOverlay(const GraphicsLayer* layer)
    419 {
    420     m_pageOverlayLayerIds.append(layer->platformLayer()->id());
    421 }
    422 
    423 void 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