1/* 2 * Copyright (C) 2012 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32 33#if ENABLE(INSPECTOR) 34 35#include "InspectorLayerTreeAgent.h" 36 37#include "InspectorDOMAgent.h" 38#include "InspectorWebFrontendDispatchers.h" 39#include "InstrumentingAgents.h" 40#include "IntRect.h" 41#include "PseudoElement.h" 42#include "RenderLayer.h" 43#include "RenderLayerBacking.h" 44#include "RenderLayerCompositor.h" 45#include "RenderView.h" 46#include <inspector/IdentifiersFactory.h> 47 48using namespace Inspector; 49 50namespace WebCore { 51 52InspectorLayerTreeAgent::InspectorLayerTreeAgent(InstrumentingAgents* instrumentingAgents) 53 : InspectorAgentBase(ASCIILiteral("LayerTree"), instrumentingAgents) 54{ 55} 56 57InspectorLayerTreeAgent::~InspectorLayerTreeAgent() 58{ 59 reset(); 60} 61 62void InspectorLayerTreeAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher) 63{ 64 m_frontendDispatcher = std::make_unique<InspectorLayerTreeFrontendDispatcher>(frontendChannel); 65 m_backendDispatcher = InspectorLayerTreeBackendDispatcher::create(backendDispatcher, this); 66} 67 68void InspectorLayerTreeAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason) 69{ 70 m_frontendDispatcher = nullptr; 71 m_backendDispatcher.clear(); 72 73 disable(nullptr); 74} 75 76void InspectorLayerTreeAgent::reset() 77{ 78 m_documentLayerToIdMap.clear(); 79 m_idToLayer.clear(); 80 m_pseudoElementToIdMap.clear(); 81 m_idToPseudoElement.clear(); 82} 83 84void InspectorLayerTreeAgent::enable(ErrorString*) 85{ 86 m_instrumentingAgents->setInspectorLayerTreeAgent(this); 87} 88 89void InspectorLayerTreeAgent::disable(ErrorString*) 90{ 91 m_instrumentingAgents->setInspectorLayerTreeAgent(nullptr); 92} 93 94void InspectorLayerTreeAgent::layerTreeDidChange() 95{ 96 m_frontendDispatcher->layerTreeDidChange(); 97} 98 99void InspectorLayerTreeAgent::renderLayerDestroyed(const RenderLayer* renderLayer) 100{ 101 unbind(renderLayer); 102} 103 104void InspectorLayerTreeAgent::pseudoElementDestroyed(PseudoElement* pseudoElement) 105{ 106 unbindPseudoElement(pseudoElement); 107} 108 109void InspectorLayerTreeAgent::layersForNode(ErrorString* errorString, int nodeId, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::LayerTree::Layer>>& layers) 110{ 111 layers = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::LayerTree::Layer>::create(); 112 113 Node* node = m_instrumentingAgents->inspectorDOMAgent()->nodeForId(nodeId); 114 if (!node) { 115 *errorString = "Provided node id doesn't match any known node"; 116 return; 117 } 118 119 RenderObject* renderer = node->renderer(); 120 if (!renderer) { 121 *errorString = "Node for provided node id doesn't have a renderer"; 122 return; 123 } 124 125 gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers); 126} 127 128void InspectorLayerTreeAgent::gatherLayersUsingRenderObjectHierarchy(ErrorString* errorString, RenderObject* renderer, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::LayerTree::Layer>>& layers) 129{ 130 if (renderer->hasLayer()) { 131 gatherLayersUsingRenderLayerHierarchy(errorString, toRenderLayerModelObject(renderer)->layer(), layers); 132 return; 133 } 134 135 for (renderer = renderer->firstChildSlow(); renderer; renderer = renderer->nextSibling()) 136 gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers); 137} 138 139void InspectorLayerTreeAgent::gatherLayersUsingRenderLayerHierarchy(ErrorString* errorString, RenderLayer* renderLayer, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::LayerTree::Layer>>& layers) 140{ 141 if (renderLayer->isComposited()) 142 layers->addItem(buildObjectForLayer(errorString, renderLayer)); 143 144 for (renderLayer = renderLayer->firstChild(); renderLayer; renderLayer = renderLayer->nextSibling()) 145 gatherLayersUsingRenderLayerHierarchy(errorString, renderLayer, layers); 146} 147 148PassRefPtr<Inspector::TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForLayer(ErrorString* errorString, RenderLayer* renderLayer) 149{ 150 RenderObject* renderer = &renderLayer->renderer(); 151 RenderLayerBacking* backing = renderLayer->backing(); 152 Node* node = renderer->node(); 153 154 bool isReflection = renderLayer->isReflection(); 155 bool isGenerated = (isReflection ? renderer->parent() : renderer)->isBeforeOrAfterContent(); 156 bool isAnonymous = renderer->isAnonymous(); 157 158 if (renderer->isRenderView()) 159 node = &renderer->document(); 160 else if (isReflection && isGenerated) 161 node = renderer->parent()->generatingElement(); 162 else if (isGenerated) 163 node = renderer->generatingNode(); 164 else if (isReflection || isAnonymous) 165 node = renderer->parent()->element(); 166 167 // Basic set of properties. 168 RefPtr<Inspector::TypeBuilder::LayerTree::Layer> layerObject = Inspector::TypeBuilder::LayerTree::Layer::create() 169 .setLayerId(bind(renderLayer)) 170 .setNodeId(idForNode(errorString, node)) 171 .setBounds(buildObjectForIntRect(renderer->absoluteBoundingBoxRect())) 172 .setMemory(backing->backingStoreMemoryEstimate()) 173 .setCompositedBounds(buildObjectForIntRect(enclosingIntRect(backing->compositedBounds()))) 174 .setPaintCount(backing->graphicsLayer()->repaintCount()); 175 176 if (node && node->shadowHost()) 177 layerObject->setIsInShadowTree(true); 178 179 if (isReflection) 180 layerObject->setIsReflection(true); 181 182 if (isGenerated) { 183 if (isReflection) 184 renderer = renderer->parent(); 185 layerObject->setIsGeneratedContent(true); 186 layerObject->setPseudoElementId(bindPseudoElement(toPseudoElement(renderer->node()))); 187 if (renderer->isBeforeContent()) 188 layerObject->setPseudoElement("before"); 189 else if (renderer->isAfterContent()) 190 layerObject->setPseudoElement("after"); 191 } 192 193 // FIXME: RenderView is now really anonymous but don't tell about it to the frontend before making sure it can handle it. 194 if (isAnonymous && !renderer->isRenderView()) { 195 layerObject->setIsAnonymous(true); 196 const RenderStyle& style = renderer->style(); 197 if (style.styleType() == FIRST_LETTER) 198 layerObject->setPseudoElement("first-letter"); 199 else if (style.styleType() == FIRST_LINE) 200 layerObject->setPseudoElement("first-line"); 201 } 202 203 return layerObject; 204} 205 206int InspectorLayerTreeAgent::idForNode(ErrorString* errorString, Node* node) 207{ 208 if (!node) 209 return 0; 210 211 InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent(); 212 213 int nodeId = domAgent->boundNodeId(node); 214 if (!nodeId) 215 nodeId = domAgent->pushNodeToFrontend(errorString, domAgent->boundNodeId(&node->document()), node); 216 217 return nodeId; 218} 219 220PassRefPtr<Inspector::TypeBuilder::LayerTree::IntRect> InspectorLayerTreeAgent::buildObjectForIntRect(const IntRect& rect) 221{ 222 return Inspector::TypeBuilder::LayerTree::IntRect::create() 223 .setX(rect.x()) 224 .setY(rect.y()) 225 .setWidth(rect.width()) 226 .setHeight(rect.height()).release(); 227} 228 229void InspectorLayerTreeAgent::reasonsForCompositingLayer(ErrorString* errorString, const String& layerId, RefPtr<Inspector::TypeBuilder::LayerTree::CompositingReasons>& compositingReasons) 230{ 231 const RenderLayer* renderLayer = m_idToLayer.get(layerId); 232 233 if (!renderLayer) { 234 *errorString = "Could not find a bound layer for the provided id"; 235 return; 236 } 237 238 CompositingReasons reasonsBitmask = renderLayer->compositor().reasonsForCompositing(*renderLayer); 239 compositingReasons = Inspector::TypeBuilder::LayerTree::CompositingReasons::create(); 240 241 if (reasonsBitmask & CompositingReason3DTransform) 242 compositingReasons->setTransform3D(true); 243 244 if (reasonsBitmask & CompositingReasonVideo) 245 compositingReasons->setVideo(true); 246 else if (reasonsBitmask & CompositingReasonCanvas) 247 compositingReasons->setCanvas(true); 248 else if (reasonsBitmask & CompositingReasonPlugin) 249 compositingReasons->setPlugin(true); 250 else if (reasonsBitmask & CompositingReasonIFrame) 251 compositingReasons->setIFrame(true); 252 253 if (reasonsBitmask & CompositingReasonBackfaceVisibilityHidden) 254 compositingReasons->setBackfaceVisibilityHidden(true); 255 256 if (reasonsBitmask & CompositingReasonClipsCompositingDescendants) 257 compositingReasons->setClipsCompositingDescendants(true); 258 259 if (reasonsBitmask & CompositingReasonAnimation) 260 compositingReasons->setAnimation(true); 261 262 if (reasonsBitmask & CompositingReasonFilters) 263 compositingReasons->setFilters(true); 264 265 if (reasonsBitmask & CompositingReasonPositionFixed) 266 compositingReasons->setPositionFixed(true); 267 268 if (reasonsBitmask & CompositingReasonPositionSticky) 269 compositingReasons->setPositionSticky(true); 270 271 if (reasonsBitmask & CompositingReasonOverflowScrollingTouch) 272 compositingReasons->setOverflowScrollingTouch(true); 273 274 if (reasonsBitmask & CompositingReasonStacking) 275 compositingReasons->setStacking(true); 276 277 if (reasonsBitmask & CompositingReasonOverlap) 278 compositingReasons->setOverlap(true); 279 280 if (reasonsBitmask & CompositingReasonNegativeZIndexChildren) 281 compositingReasons->setNegativeZIndexChildren(true); 282 283 if (reasonsBitmask & CompositingReasonTransformWithCompositedDescendants) 284 compositingReasons->setTransformWithCompositedDescendants(true); 285 286 if (reasonsBitmask & CompositingReasonOpacityWithCompositedDescendants) 287 compositingReasons->setOpacityWithCompositedDescendants(true); 288 289 if (reasonsBitmask & CompositingReasonMaskWithCompositedDescendants) 290 compositingReasons->setMaskWithCompositedDescendants(true); 291 292 if (reasonsBitmask & CompositingReasonReflectionWithCompositedDescendants) 293 compositingReasons->setReflectionWithCompositedDescendants(true); 294 295 if (reasonsBitmask & CompositingReasonFilterWithCompositedDescendants) 296 compositingReasons->setFilterWithCompositedDescendants(true); 297 298 if (reasonsBitmask & CompositingReasonBlendingWithCompositedDescendants) 299 compositingReasons->setBlendingWithCompositedDescendants(true); 300 301 if (reasonsBitmask & CompositingReasonIsolatesCompositedBlendingDescendants) 302 compositingReasons->setIsolatesCompositedBlendingDescendants(true); 303 304 if (reasonsBitmask & CompositingReasonPerspective) 305 compositingReasons->setPerspective(true); 306 307 if (reasonsBitmask & CompositingReasonPreserve3D) 308 compositingReasons->setPreserve3D(true); 309 310 if (reasonsBitmask & CompositingReasonRoot) 311 compositingReasons->setRoot(true); 312} 313 314String InspectorLayerTreeAgent::bind(const RenderLayer* layer) 315{ 316 if (!layer) 317 return emptyString(); 318 String identifier = m_documentLayerToIdMap.get(layer); 319 if (identifier.isNull()) { 320 identifier = IdentifiersFactory::createIdentifier(); 321 m_documentLayerToIdMap.set(layer, identifier); 322 m_idToLayer.set(identifier, layer); 323 } 324 return identifier; 325} 326 327void InspectorLayerTreeAgent::unbind(const RenderLayer* layer) 328{ 329 HashMap<const RenderLayer*, String>::iterator iterator = m_documentLayerToIdMap.find(layer); 330 if (iterator == m_documentLayerToIdMap.end()) 331 return; 332 m_idToLayer.remove(iterator->value); 333 m_documentLayerToIdMap.remove(iterator); 334} 335 336String InspectorLayerTreeAgent::bindPseudoElement(PseudoElement* pseudoElement) 337{ 338 if (!pseudoElement) 339 return emptyString(); 340 String identifier = m_pseudoElementToIdMap.get(pseudoElement); 341 if (identifier.isNull()) { 342 identifier = IdentifiersFactory::createIdentifier(); 343 m_pseudoElementToIdMap.set(pseudoElement, identifier); 344 m_idToPseudoElement.set(identifier, pseudoElement); 345 } 346 return identifier; 347} 348 349void InspectorLayerTreeAgent::unbindPseudoElement(PseudoElement* pseudoElement) 350{ 351 HashMap<PseudoElement*, String>::iterator iterator = m_pseudoElementToIdMap.find(pseudoElement); 352 if (iterator == m_pseudoElementToIdMap.end()) 353 return; 354 m_idToPseudoElement.remove(iterator->value); 355 m_pseudoElementToIdMap.remove(iterator); 356} 357 358} // namespace WebCore 359 360#endif // ENABLE(INSPECTOR) 361