will-change should sometimes trigger compositing
[WebKit-https.git] / Source / WebCore / inspector / InspectorLayerTreeAgent.cpp
index 5119ccc..d43b69c 100644 (file)
  */
 
 #include "config.h"
-
-#if USE(ACCELERATED_COMPOSITING)
-#if ENABLE(INSPECTOR)
-
 #include "InspectorLayerTreeAgent.h"
 
-#include "IdentifiersFactory.h"
 #include "InspectorDOMAgent.h"
-#include "InspectorFrontend.h"
-#include "InspectorState.h"
+#include <inspector/InspectorFrontendDispatchers.h>
 #include "InstrumentingAgents.h"
 #include "IntRect.h"
+#include "PseudoElement.h"
 #include "RenderLayer.h"
 #include "RenderLayerBacking.h"
+#include "RenderLayerCompositor.h"
 #include "RenderView.h"
+#include <inspector/IdentifiersFactory.h>
 
-namespace WebCore {
+using namespace Inspector;
 
-namespace LayerTreeAgentState {
-static const char layerTreeAgentEnabled[] = "layerTreeAgentEnabled";
-};
+namespace WebCore {
 
-InspectorLayerTreeAgent::InspectorLayerTreeAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state)
-    : InspectorBaseAgent<InspectorLayerTreeAgent>("LayerTree", instrumentingAgents, state)
-    , m_frontend(0)
+InspectorLayerTreeAgent::InspectorLayerTreeAgent(InstrumentingAgents* instrumentingAgents)
+    : InspectorAgentBase(ASCIILiteral("LayerTree"), instrumentingAgents)
 {
 }
 
@@ -62,84 +56,85 @@ InspectorLayerTreeAgent::~InspectorLayerTreeAgent()
     reset();
 }
 
-void InspectorLayerTreeAgent::setFrontend(InspectorFrontend* frontend)
+void InspectorLayerTreeAgent::didCreateFrontendAndBackend(Inspector::FrontendChannel* frontendChannel, Inspector::BackendDispatcher* backendDispatcher)
 {
-    m_frontend = frontend->layertree();
+    m_frontendDispatcher = std::make_unique<Inspector::LayerTreeFrontendDispatcher>(frontendChannel);
+    m_backendDispatcher = Inspector::LayerTreeBackendDispatcher::create(backendDispatcher, this);
 }
 
-void InspectorLayerTreeAgent::clearFrontend()
+void InspectorLayerTreeAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
 {
-    m_frontend = 0;
-    disable(0);
-}
+    m_frontendDispatcher = nullptr;
+    m_backendDispatcher = nullptr;
 
-void InspectorLayerTreeAgent::restore()
-{
-    if (m_state->getBoolean(LayerTreeAgentState::layerTreeAgentEnabled))
-        enable(0);
+    ErrorString unused;
+    disable(unused);
 }
 
 void InspectorLayerTreeAgent::reset()
 {
     m_documentLayerToIdMap.clear();
     m_idToLayer.clear();
+    m_pseudoElementToIdMap.clear();
+    m_idToPseudoElement.clear();
 }
 
-void InspectorLayerTreeAgent::enable(ErrorString*)
+void InspectorLayerTreeAgent::enable(ErrorString&)
 {
-    m_state->setBoolean(LayerTreeAgentState::layerTreeAgentEnabled, true);
     m_instrumentingAgents->setInspectorLayerTreeAgent(this);
 }
 
-void InspectorLayerTreeAgent::disable(ErrorString*)
+void InspectorLayerTreeAgent::disable(ErrorString&)
 {
-    if (!m_state->getBoolean(LayerTreeAgentState::layerTreeAgentEnabled))
-        return;
-    m_state->setBoolean(LayerTreeAgentState::layerTreeAgentEnabled, false);
-    m_instrumentingAgents->setInspectorLayerTreeAgent(0);
+    m_instrumentingAgents->setInspectorLayerTreeAgent(nullptr);
 }
 
 void InspectorLayerTreeAgent::layerTreeDidChange()
 {
-    m_frontend->layerTreeDidChange();
+    m_frontendDispatcher->layerTreeDidChange();
+}
+
+void InspectorLayerTreeAgent::renderLayerDestroyed(const RenderLayer& renderLayer)
+{
+    unbind(&renderLayer);
 }
 
-void InspectorLayerTreeAgent::renderLayerDestroyed(const RenderLayer* renderLayer)
+void InspectorLayerTreeAgent::pseudoElementDestroyed(PseudoElement& pseudoElement)
 {
-    unbind(renderLayer);
+    unbindPseudoElement(&pseudoElement);
 }
 
-void InspectorLayerTreeAgent::layersForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
+void InspectorLayerTreeAgent::layersForNode(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::LayerTree::Layer>>& layers)
 {
-    layers = TypeBuilder::Array<TypeBuilder::LayerTree::Layer>::create();
+    layers = Inspector::Protocol::Array<Inspector::Protocol::LayerTree::Layer>::create();
 
     Node* node = m_instrumentingAgents->inspectorDOMAgent()->nodeForId(nodeId);
     if (!node) {
-        *errorString = "Provided node id doesn't match any known node";
+        errorString = ASCIILiteral("Provided node id doesn't match any known node");
         return;
     }
 
     RenderObject* renderer = node->renderer();
     if (!renderer) {
-        *errorString = "Node for provided node id doesn't have a renderer";
+        errorString = ASCIILiteral("Node for provided node id doesn't have a renderer");
         return;
     }
 
     gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers);
 }
 
-void InspectorLayerTreeAgent::gatherLayersUsingRenderObjectHierarchy(ErrorString* errorString, RenderObject* renderer, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
+void InspectorLayerTreeAgent::gatherLayersUsingRenderObjectHierarchy(ErrorString& errorString, RenderObject* renderer, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::LayerTree::Layer>>& layers)
 {
     if (renderer->hasLayer()) {
-        gatherLayersUsingRenderLayerHierarchy(errorString, toRenderLayerModelObject(renderer)->layer(), layers);
+        gatherLayersUsingRenderLayerHierarchy(errorString, downcast<RenderLayerModelObject>(*renderer).layer(), layers);
         return;
     }
 
-    for (renderer = renderer->firstChild(); renderer; renderer = renderer->nextSibling())
+    for (renderer = renderer->firstChildSlow(); renderer; renderer = renderer->nextSibling())
         gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers);
 }
 
-void InspectorLayerTreeAgent::gatherLayersUsingRenderLayerHierarchy(ErrorString* errorString, RenderLayer* renderLayer, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers)
+void InspectorLayerTreeAgent::gatherLayersUsingRenderLayerHierarchy(ErrorString& errorString, RenderLayer* renderLayer, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::LayerTree::Layer>>& layers)
 {
     if (renderLayer->isComposited())
         layers->addItem(buildObjectForLayer(errorString, renderLayer));
@@ -148,22 +143,34 @@ void InspectorLayerTreeAgent::gatherLayersUsingRenderLayerHierarchy(ErrorString*
         gatherLayersUsingRenderLayerHierarchy(errorString, renderLayer, layers);
 }
 
-PassRefPtr<TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForLayer(ErrorString* errorString, RenderLayer* renderLayer)
+Ref<Inspector::Protocol::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForLayer(ErrorString& errorString, RenderLayer* renderLayer)
 {
-    bool isReflection = renderLayer->isReflection();
-
-    RenderObject* renderer = renderLayer->renderer();
+    RenderObject* renderer = &renderLayer->renderer();
     RenderLayerBacking* backing = renderLayer->backing();
-    Node* node = isReflection ? renderer->parent()->node() : renderer->node();
+    Node* node = renderer->node();
+
+    bool isReflection = renderLayer->isReflection();
+    bool isGenerated = (isReflection ? renderer->parent() : renderer)->isBeforeOrAfterContent();
+    bool isAnonymous = renderer->isAnonymous();
+
+    if (renderer->isRenderView())
+        node = &renderer->document();
+    else if (isReflection && isGenerated)
+        node = renderer->parent()->generatingElement();
+    else if (isGenerated)
+        node = renderer->generatingNode();
+    else if (isReflection || isAnonymous)
+        node = renderer->parent()->element();
 
     // Basic set of properties.
-    RefPtr<TypeBuilder::LayerTree::Layer> layerObject = TypeBuilder::LayerTree::Layer::create()
+    auto layerObject = Inspector::Protocol::LayerTree::Layer::create()
         .setLayerId(bind(renderLayer))
         .setNodeId(idForNode(errorString, node))
-        .setBounds(buildObjectForIntRect(enclosingIntRect(renderer->absoluteBoundingBoxRect())))
+        .setBounds(buildObjectForIntRect(renderer->absoluteBoundingBoxRect()))
         .setMemory(backing->backingStoreMemoryEstimate())
-        .setCompositedBounds(buildObjectForIntRect(backing->compositedBounds()))
-        .setPaintCount(backing->graphicsLayer()->repaintCount());
+        .setCompositedBounds(buildObjectForIntRect(enclosingIntRect(backing->compositedBounds())))
+        .setPaintCount(backing->graphicsLayer()->repaintCount())
+        .release();
 
     if (node && node->shadowHost())
         layerObject->setIsInShadowTree(true);
@@ -171,33 +178,148 @@ PassRefPtr<TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectFo
     if (isReflection)
         layerObject->setIsReflection(true);
 
-    return layerObject;
+    if (isGenerated) {
+        if (isReflection)
+            renderer = renderer->parent();
+        layerObject->setIsGeneratedContent(true);
+        layerObject->setPseudoElementId(bindPseudoElement(downcast<PseudoElement>(renderer->node())));
+        if (renderer->isBeforeContent())
+            layerObject->setPseudoElement("before");
+        else if (renderer->isAfterContent())
+            layerObject->setPseudoElement("after");
+    }
+
+    // FIXME: RenderView is now really anonymous but don't tell about it to the frontend before making sure it can handle it.
+    if (isAnonymous && !renderer->isRenderView()) {
+        layerObject->setIsAnonymous(true);
+        const RenderStyle& style = renderer->style();
+        if (style.styleType() == FIRST_LETTER)
+            layerObject->setPseudoElement("first-letter");
+        else if (style.styleType() == FIRST_LINE)
+            layerObject->setPseudoElement("first-line");
+    }
+
+    return WTF::move(layerObject);
 }
 
-int InspectorLayerTreeAgent::idForNode(ErrorString* errorString, Node* node)
+int InspectorLayerTreeAgent::idForNode(ErrorString& errorString, Node* node)
 {
+    if (!node)
+        return 0;
+
     InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent();
     
     int nodeId = domAgent->boundNodeId(node);
     if (!nodeId)
-        nodeId = domAgent->pushNodeToFrontend(errorString, domAgent->boundNodeId(node->document()), node);
+        nodeId = domAgent->pushNodeToFrontend(errorString, domAgent->boundNodeId(&node->document()), node);
 
     return nodeId;
 }
 
-PassRefPtr<TypeBuilder::LayerTree::IntRect> InspectorLayerTreeAgent::buildObjectForIntRect(const IntRect& rect)
+Ref<Inspector::Protocol::LayerTree::IntRect> InspectorLayerTreeAgent::buildObjectForIntRect(const IntRect& rect)
 {
-    return TypeBuilder::LayerTree::IntRect::create()
+    return Inspector::Protocol::LayerTree::IntRect::create()
         .setX(rect.x())
         .setY(rect.y())
         .setWidth(rect.width())
-        .setHeight(rect.height()).release();
+        .setHeight(rect.height())
+        .release();
+}
+
+void InspectorLayerTreeAgent::reasonsForCompositingLayer(ErrorString& errorString, const String& layerId, RefPtr<Inspector::Protocol::LayerTree::CompositingReasons>& compositingReasonsResult)
+{
+    const RenderLayer* renderLayer = m_idToLayer.get(layerId);
+
+    if (!renderLayer) {
+        errorString = ASCIILiteral("Could not find a bound layer for the provided id");
+        return;
+    }
+
+    CompositingReasons reasonsBitmask = renderLayer->compositor().reasonsForCompositing(*renderLayer);
+    auto compositingReasons = Inspector::Protocol::LayerTree::CompositingReasons::create().release();
+
+    if (reasonsBitmask & CompositingReason3DTransform)
+        compositingReasons->setTransform3D(true);
+
+    if (reasonsBitmask & CompositingReasonVideo)
+        compositingReasons->setVideo(true);
+    else if (reasonsBitmask & CompositingReasonCanvas)
+        compositingReasons->setCanvas(true);
+    else if (reasonsBitmask & CompositingReasonPlugin)
+        compositingReasons->setPlugin(true);
+    else if (reasonsBitmask & CompositingReasonIFrame)
+        compositingReasons->setIFrame(true);
+    
+    if (reasonsBitmask & CompositingReasonBackfaceVisibilityHidden)
+        compositingReasons->setBackfaceVisibilityHidden(true);
+
+    if (reasonsBitmask & CompositingReasonClipsCompositingDescendants)
+        compositingReasons->setClipsCompositingDescendants(true);
+
+    if (reasonsBitmask & CompositingReasonAnimation)
+        compositingReasons->setAnimation(true);
+
+    if (reasonsBitmask & CompositingReasonFilters)
+        compositingReasons->setFilters(true);
+
+    if (reasonsBitmask & CompositingReasonPositionFixed)
+        compositingReasons->setPositionFixed(true);
+
+    if (reasonsBitmask & CompositingReasonPositionSticky)
+        compositingReasons->setPositionSticky(true);
+
+    if (reasonsBitmask & CompositingReasonOverflowScrollingTouch)
+        compositingReasons->setOverflowScrollingTouch(true);
+
+    if (reasonsBitmask & CompositingReasonStacking)
+        compositingReasons->setStacking(true);
+
+    if (reasonsBitmask & CompositingReasonOverlap)
+        compositingReasons->setOverlap(true);
+
+    if (reasonsBitmask & CompositingReasonNegativeZIndexChildren)
+        compositingReasons->setNegativeZIndexChildren(true);
+
+    if (reasonsBitmask & CompositingReasonTransformWithCompositedDescendants)
+        compositingReasons->setTransformWithCompositedDescendants(true);
+
+    if (reasonsBitmask & CompositingReasonOpacityWithCompositedDescendants)
+        compositingReasons->setOpacityWithCompositedDescendants(true);
+
+    if (reasonsBitmask & CompositingReasonMaskWithCompositedDescendants)
+        compositingReasons->setMaskWithCompositedDescendants(true);
+
+    if (reasonsBitmask & CompositingReasonReflectionWithCompositedDescendants)
+        compositingReasons->setReflectionWithCompositedDescendants(true);
+
+    if (reasonsBitmask & CompositingReasonFilterWithCompositedDescendants)
+        compositingReasons->setFilterWithCompositedDescendants(true);
+
+    if (reasonsBitmask & CompositingReasonBlendingWithCompositedDescendants)
+        compositingReasons->setBlendingWithCompositedDescendants(true);
+
+    if (reasonsBitmask & CompositingReasonIsolatesCompositedBlendingDescendants)
+        compositingReasons->setIsolatesCompositedBlendingDescendants(true);
+
+    if (reasonsBitmask & CompositingReasonPerspective)
+        compositingReasons->setPerspective(true);
+
+    if (reasonsBitmask & CompositingReasonPreserve3D)
+        compositingReasons->setPreserve3D(true);
+
+    if (reasonsBitmask & CompositingReasonWillChange)
+        compositingReasons->setWillChange(true);
+
+    if (reasonsBitmask & CompositingReasonRoot)
+        compositingReasons->setRoot(true);
+    
+    compositingReasonsResult = WTF::move(compositingReasons);
 }
 
 String InspectorLayerTreeAgent::bind(const RenderLayer* layer)
 {
     if (!layer)
-        return "";
+        return emptyString();
     String identifier = m_documentLayerToIdMap.get(layer);
     if (identifier.isNull()) {
         identifier = IdentifiersFactory::createIdentifier();
@@ -209,15 +331,33 @@ String InspectorLayerTreeAgent::bind(const RenderLayer* layer)
 
 void InspectorLayerTreeAgent::unbind(const RenderLayer* layer)
 {
-    String identifier = m_documentLayerToIdMap.get(layer);
-    if (identifier.isNull())
+    HashMap<const RenderLayer*, String>::iterator iterator = m_documentLayerToIdMap.find(layer);
+    if (iterator == m_documentLayerToIdMap.end())
         return;
+    m_idToLayer.remove(iterator->value);
+    m_documentLayerToIdMap.remove(iterator);
+}
 
-    m_documentLayerToIdMap.remove(layer);
-    m_idToLayer.remove(identifier);
+String InspectorLayerTreeAgent::bindPseudoElement(PseudoElement* pseudoElement)
+{
+    if (!pseudoElement)
+        return emptyString();
+    String identifier = m_pseudoElementToIdMap.get(pseudoElement);
+    if (identifier.isNull()) {
+        identifier = IdentifiersFactory::createIdentifier();
+        m_pseudoElementToIdMap.set(pseudoElement, identifier);
+        m_idToPseudoElement.set(identifier, pseudoElement);
+    }
+    return identifier;
 }
 
-} // namespace WebCore
+void InspectorLayerTreeAgent::unbindPseudoElement(PseudoElement* pseudoElement)
+{
+    HashMap<PseudoElement*, String>::iterator iterator = m_pseudoElementToIdMap.find(pseudoElement);
+    if (iterator == m_pseudoElementToIdMap.end())
+        return;
+    m_idToPseudoElement.remove(iterator->value);
+    m_pseudoElementToIdMap.remove(iterator);
+}
 
-#endif // ENABLE(INSPECTOR)
-#endif // USE(ACCELERATED_COMPOSITING)
+} // namespace WebCore