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/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 
     58 inline String idForLayer(const GraphicsLayer* graphicsLayer)
     59 {
     60     return String::number(graphicsLayer->platformLayer()->id());
     61 }
     62 
     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 
     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 
     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 
    140 InspectorLayerTreeAgent::InspectorLayerTreeAgent(Page* page)
    141     : InspectorBaseAgent<InspectorLayerTreeAgent>("LayerTree")
    142     , m_frontend(0)
    143     , m_page(page)
    144 {
    145 }
    146 
    147 InspectorLayerTreeAgent::~InspectorLayerTreeAgent()
    148 {
    149 }
    150 
    151 void InspectorLayerTreeAgent::setFrontend(InspectorFrontend* frontend)
    152 {
    153     m_frontend = frontend->layertree();
    154 }
    155 
    156 void InspectorLayerTreeAgent::clearFrontend()
    157 {
    158     m_frontend = 0;
    159     disable(0);
    160 }
    161 
    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 
    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 
    179 void InspectorLayerTreeAgent::disable(ErrorString*)
    180 {
    181     m_instrumentingAgents->setInspectorLayerTreeAgent(0);
    182     m_snapshotById.clear();
    183     ErrorString unused;
    184 }
    185 
    186 void InspectorLayerTreeAgent::layerTreeDidChange()
    187 {
    188     m_frontend->layerTreeDidChange(buildLayerTree());
    189 }
    190 
    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 
    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 
    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 
    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 
    249 int InspectorLayerTreeAgent::idForNode(Node* node)
    250 {
    251     return InspectorNodeIds::idForNode(node);
    252 }
    253 
    254 RenderLayerCompositor* InspectorLayerTreeAgent::renderLayerCompositor()
    255 {
    256     RenderView* renderView = m_page->deprecatedLocalMainFrame()->contentRenderer();
    257     RenderLayerCompositor* compositor = renderView ? renderView->compositor() : 0;
    258     return compositor;
    259 }
    260 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    400 void InspectorLayerTreeAgent::willAddPageOverlay(const GraphicsLayer* layer)
    401 {
    402     m_pageOverlayLayerIds.append(layer->platformLayer()->id());
    403 }
    404 
    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