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 USE(ACCELERATED_COMPOSITING) 34#if ENABLE(INSPECTOR) 35 36#include "InspectorLayerTreeAgent.h" 37 38#include "IdentifiersFactory.h" 39#include "InspectorDOMAgent.h" 40#include "InspectorFrontend.h" 41#include "InspectorState.h" 42#include "InstrumentingAgents.h" 43#include "IntRect.h" 44#include "PseudoElement.h" 45#include "RenderLayer.h" 46#include "RenderLayerBacking.h" 47#include "RenderLayerCompositor.h" 48#include "RenderView.h" 49 50namespace WebCore { 51 52namespace LayerTreeAgentState { 53static const char layerTreeAgentEnabled[] = "layerTreeAgentEnabled"; 54}; 55 56InspectorLayerTreeAgent::InspectorLayerTreeAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state) 57 : InspectorBaseAgent<InspectorLayerTreeAgent>("LayerTree", instrumentingAgents, state) 58 , m_frontend(0) 59{ 60} 61 62InspectorLayerTreeAgent::~InspectorLayerTreeAgent() 63{ 64 reset(); 65} 66 67void InspectorLayerTreeAgent::setFrontend(InspectorFrontend* frontend) 68{ 69 m_frontend = frontend->layertree(); 70} 71 72void InspectorLayerTreeAgent::clearFrontend() 73{ 74 m_frontend = 0; 75 disable(0); 76} 77 78void InspectorLayerTreeAgent::restore() 79{ 80 if (m_state->getBoolean(LayerTreeAgentState::layerTreeAgentEnabled)) 81 enable(0); 82} 83 84void InspectorLayerTreeAgent::reset() 85{ 86 m_documentLayerToIdMap.clear(); 87 m_idToLayer.clear(); 88 m_pseudoElementToIdMap.clear(); 89 m_idToPseudoElement.clear(); 90} 91 92void InspectorLayerTreeAgent::enable(ErrorString*) 93{ 94 m_state->setBoolean(LayerTreeAgentState::layerTreeAgentEnabled, true); 95 m_instrumentingAgents->setInspectorLayerTreeAgent(this); 96} 97 98void InspectorLayerTreeAgent::disable(ErrorString*) 99{ 100 if (!m_state->getBoolean(LayerTreeAgentState::layerTreeAgentEnabled)) 101 return; 102 m_state->setBoolean(LayerTreeAgentState::layerTreeAgentEnabled, false); 103 m_instrumentingAgents->setInspectorLayerTreeAgent(0); 104} 105 106void InspectorLayerTreeAgent::layerTreeDidChange() 107{ 108 m_frontend->layerTreeDidChange(); 109} 110 111void InspectorLayerTreeAgent::renderLayerDestroyed(const RenderLayer* renderLayer) 112{ 113 unbind(renderLayer); 114} 115 116void InspectorLayerTreeAgent::pseudoElementDestroyed(PseudoElement* pseudoElement) 117{ 118 unbindPseudoElement(pseudoElement); 119} 120 121void InspectorLayerTreeAgent::layersForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers) 122{ 123 layers = TypeBuilder::Array<TypeBuilder::LayerTree::Layer>::create(); 124 125 Node* node = m_instrumentingAgents->inspectorDOMAgent()->nodeForId(nodeId); 126 if (!node) { 127 *errorString = "Provided node id doesn't match any known node"; 128 return; 129 } 130 131 RenderObject* renderer = node->renderer(); 132 if (!renderer) { 133 *errorString = "Node for provided node id doesn't have a renderer"; 134 return; 135 } 136 137 gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers); 138} 139 140void InspectorLayerTreeAgent::gatherLayersUsingRenderObjectHierarchy(ErrorString* errorString, RenderObject* renderer, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers) 141{ 142 if (renderer->hasLayer()) { 143 gatherLayersUsingRenderLayerHierarchy(errorString, toRenderLayerModelObject(renderer)->layer(), layers); 144 return; 145 } 146 147 for (renderer = renderer->firstChild(); renderer; renderer = renderer->nextSibling()) 148 gatherLayersUsingRenderObjectHierarchy(errorString, renderer, layers); 149} 150 151void InspectorLayerTreeAgent::gatherLayersUsingRenderLayerHierarchy(ErrorString* errorString, RenderLayer* renderLayer, RefPtr<TypeBuilder::Array<TypeBuilder::LayerTree::Layer> >& layers) 152{ 153 if (renderLayer->isComposited()) 154 layers->addItem(buildObjectForLayer(errorString, renderLayer)); 155 156 for (renderLayer = renderLayer->firstChild(); renderLayer; renderLayer = renderLayer->nextSibling()) 157 gatherLayersUsingRenderLayerHierarchy(errorString, renderLayer, layers); 158} 159 160PassRefPtr<TypeBuilder::LayerTree::Layer> InspectorLayerTreeAgent::buildObjectForLayer(ErrorString* errorString, RenderLayer* renderLayer) 161{ 162 RenderObject* renderer = renderLayer->renderer(); 163 RenderLayerBacking* backing = renderLayer->backing(); 164 Node* node = renderer->node(); 165 166 bool isReflection = renderLayer->isReflection(); 167 bool isGenerated = (isReflection ? renderer->parent() : renderer)->isBeforeOrAfterContent(); 168 bool isAnonymous = renderer->isAnonymous(); 169 170 if (isReflection && isGenerated) 171 node = renderer->parent()->generatingNode(); 172 else if (isGenerated) 173 node = renderer->generatingNode(); 174 else if (isReflection || isAnonymous) 175 node = renderer->parent()->node(); 176 177 // Basic set of properties. 178 RefPtr<TypeBuilder::LayerTree::Layer> layerObject = TypeBuilder::LayerTree::Layer::create() 179 .setLayerId(bind(renderLayer)) 180 .setNodeId(idForNode(errorString, node)) 181 .setBounds(buildObjectForIntRect(renderer->absoluteBoundingBoxRect())) 182 .setMemory(backing->backingStoreMemoryEstimate()) 183 .setCompositedBounds(buildObjectForIntRect(backing->compositedBounds())) 184 .setPaintCount(backing->graphicsLayer()->repaintCount()); 185 186 if (node && node->shadowHost()) 187 layerObject->setIsInShadowTree(true); 188 189 if (isReflection) 190 layerObject->setIsReflection(true); 191 192 if (isGenerated) { 193 if (isReflection) 194 renderer = renderer->parent(); 195 layerObject->setIsGeneratedContent(true); 196 layerObject->setPseudoElementId(bindPseudoElement(static_cast<PseudoElement*>(renderer->node()))); 197 if (renderer->isBeforeContent()) 198 layerObject->setPseudoElement("before"); 199 else if (renderer->isAfterContent()) 200 layerObject->setPseudoElement("after"); 201 } 202 203 if (isAnonymous) { 204 layerObject->setIsAnonymous(true); 205 if (RenderStyle* style = renderer->style()) { 206 if (style->styleType() == FIRST_LETTER) 207 layerObject->setPseudoElement("first-letter"); 208 else if (style->styleType() == FIRST_LINE) 209 layerObject->setPseudoElement("first-line"); 210 } 211 } 212 213 return layerObject; 214} 215 216int InspectorLayerTreeAgent::idForNode(ErrorString* errorString, Node* node) 217{ 218 if (!node) 219 return 0; 220 221 InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent(); 222 223 int nodeId = domAgent->boundNodeId(node); 224 if (!nodeId) 225 nodeId = domAgent->pushNodeToFrontend(errorString, domAgent->boundNodeId(node->document()), node); 226 227 return nodeId; 228} 229 230PassRefPtr<TypeBuilder::LayerTree::IntRect> InspectorLayerTreeAgent::buildObjectForIntRect(const IntRect& rect) 231{ 232 return TypeBuilder::LayerTree::IntRect::create() 233 .setX(rect.x()) 234 .setY(rect.y()) 235 .setWidth(rect.width()) 236 .setHeight(rect.height()).release(); 237} 238 239void InspectorLayerTreeAgent::reasonsForCompositingLayer(ErrorString* errorString, const String& layerId, RefPtr<TypeBuilder::LayerTree::CompositingReasons>& compositingReasons) 240{ 241 const RenderLayer* renderLayer = m_idToLayer.get(layerId); 242 243 if (!renderLayer) { 244 *errorString = "Could not find a bound layer for the provided id"; 245 return; 246 } 247 248 CompositingReasons reasonsBitmask = renderLayer->compositor()->reasonsForCompositing(renderLayer); 249 compositingReasons = TypeBuilder::LayerTree::CompositingReasons::create(); 250 251 if (reasonsBitmask & CompositingReason3DTransform) 252 compositingReasons->setTransform3D(true); 253 254 if (reasonsBitmask & CompositingReasonVideo) 255 compositingReasons->setVideo(true); 256 257 if (reasonsBitmask & CompositingReasonCanvas) 258 compositingReasons->setCanvas(true); 259 260 if (reasonsBitmask & CompositingReasonPlugin) 261 compositingReasons->setPlugin(true); 262 263 if (reasonsBitmask & CompositingReasonIFrame) 264 compositingReasons->setIFrame(true); 265 266 if (reasonsBitmask & CompositingReasonBackfaceVisibilityHidden) 267 compositingReasons->setBackfaceVisibilityHidden(true); 268 269 if (reasonsBitmask & CompositingReasonClipsCompositingDescendants) 270 compositingReasons->setClipsCompositingDescendants(true); 271 272 if (reasonsBitmask & CompositingReasonAnimation) 273 compositingReasons->setAnimation(true); 274 275 if (reasonsBitmask & CompositingReasonFilters) 276 compositingReasons->setFilters(true); 277 278 if (reasonsBitmask & CompositingReasonPositionFixed) 279 compositingReasons->setPositionFixed(true); 280 281 if (reasonsBitmask & CompositingReasonPositionSticky) 282 compositingReasons->setPositionSticky(true); 283 284 if (reasonsBitmask & CompositingReasonOverflowScrollingTouch) 285 compositingReasons->setOverflowScrollingTouch(true); 286 287 if (reasonsBitmask & CompositingReasonStacking) 288 compositingReasons->setStacking(true); 289 290 if (reasonsBitmask & CompositingReasonOverlap) 291 compositingReasons->setOverlap(true); 292 293 if (reasonsBitmask & CompositingReasonNegativeZIndexChildren) 294 compositingReasons->setNegativeZIndexChildren(true); 295 296 if (reasonsBitmask & CompositingReasonTransformWithCompositedDescendants) 297 compositingReasons->setTransformWithCompositedDescendants(true); 298 299 if (reasonsBitmask & CompositingReasonOpacityWithCompositedDescendants) 300 compositingReasons->setOpacityWithCompositedDescendants(true); 301 302 if (reasonsBitmask & CompositingReasonMaskWithCompositedDescendants) 303 compositingReasons->setMaskWithCompositedDescendants(true); 304 305 if (reasonsBitmask & CompositingReasonReflectionWithCompositedDescendants) 306 compositingReasons->setReflectionWithCompositedDescendants(true); 307 308 if (reasonsBitmask & CompositingReasonFilterWithCompositedDescendants) 309 compositingReasons->setFilterWithCompositedDescendants(true); 310 311 if (reasonsBitmask & CompositingReasonBlendingWithCompositedDescendants) 312 compositingReasons->setBlendingWithCompositedDescendants(true); 313 314 if (reasonsBitmask & CompositingReasonPerspective) 315 compositingReasons->setPerspective(true); 316 317 if (reasonsBitmask & CompositingReasonPreserve3D) 318 compositingReasons->setPreserve3D(true); 319 320 if (reasonsBitmask & CompositingReasonRoot) 321 compositingReasons->setRoot(true); 322} 323 324String InspectorLayerTreeAgent::bind(const RenderLayer* layer) 325{ 326 if (!layer) 327 return emptyString(); 328 String identifier = m_documentLayerToIdMap.get(layer); 329 if (identifier.isNull()) { 330 identifier = IdentifiersFactory::createIdentifier(); 331 m_documentLayerToIdMap.set(layer, identifier); 332 m_idToLayer.set(identifier, layer); 333 } 334 return identifier; 335} 336 337void InspectorLayerTreeAgent::unbind(const RenderLayer* layer) 338{ 339 HashMap<const RenderLayer*, String>::iterator iterator = m_documentLayerToIdMap.find(layer); 340 if (iterator == m_documentLayerToIdMap.end()) 341 return; 342 m_idToLayer.remove(iterator->value); 343 m_documentLayerToIdMap.remove(iterator); 344} 345 346String InspectorLayerTreeAgent::bindPseudoElement(PseudoElement* pseudoElement) 347{ 348 if (!pseudoElement) 349 return emptyString(); 350 String identifier = m_pseudoElementToIdMap.get(pseudoElement); 351 if (identifier.isNull()) { 352 identifier = IdentifiersFactory::createIdentifier(); 353 m_pseudoElementToIdMap.set(pseudoElement, identifier); 354 m_idToPseudoElement.set(identifier, pseudoElement); 355 } 356 return identifier; 357} 358 359void InspectorLayerTreeAgent::unbindPseudoElement(PseudoElement* pseudoElement) 360{ 361 HashMap<PseudoElement*, String>::iterator iterator = m_pseudoElementToIdMap.find(pseudoElement); 362 if (iterator == m_pseudoElementToIdMap.end()) 363 return; 364 m_idToPseudoElement.remove(iterator->value); 365 m_pseudoElementToIdMap.remove(iterator); 366} 367 368} // namespace WebCore 369 370#endif // ENABLE(INSPECTOR) 371#endif // USE(ACCELERATED_COMPOSITING) 372