Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / inspector / InspectorDOMAgent.cpp
old mode 100755 (executable)
new mode 100644 (file)
index dd4a120..3fc82c1
@@ -31,7 +31,6 @@
 #include "config.h"
 #include "core/inspector/InspectorDOMAgent.h"
 
-#include "HTMLNames.h"
 #include "bindings/v8/ExceptionState.h"
 #include "bindings/v8/ScriptEventListener.h"
 #include "core/dom/Attr.h"
 #include "core/editing/markup.h"
 #include "core/fileapi/File.h"
 #include "core/fileapi/FileList.h"
+#include "core/frame/LocalFrame.h"
 #include "core/html/HTMLFrameOwnerElement.h"
 #include "core/html/HTMLInputElement.h"
+#include "core/html/HTMLLinkElement.h"
 #include "core/html/HTMLTemplateElement.h"
+#include "core/html/imports/HTMLImportChild.h"
+#include "core/html/imports/HTMLImportLoader.h"
 #include "core/inspector/DOMEditor.h"
 #include "core/inspector/DOMPatchSupport.h"
 #include "core/inspector/IdentifiersFactory.h"
 #include "core/inspector/InspectorHistory.h"
+#include "core/inspector/InspectorNodeIds.h"
 #include "core/inspector/InspectorOverlay.h"
 #include "core/inspector/InspectorPageAgent.h"
 #include "core/inspector/InspectorState.h"
 #include "core/inspector/InstrumentingAgents.h"
 #include "core/loader/DocumentLoader.h"
-#include "core/frame/Frame.h"
 #include "core/page/FrameTree.h"
 #include "core/page/Page.h"
 #include "core/rendering/HitTestResult.h"
@@ -145,7 +148,7 @@ static bool parseQuad(const RefPtr<JSONArray>& quadArray, FloatQuad* quad)
     return true;
 }
 
-static Node* hoveredNodeForPoint(Frame* frame, const IntPoint& point, bool ignorePointerEventsNone)
+static Node* hoveredNodeForPoint(LocalFrame* frame, const IntPoint& point, bool ignorePointerEventsNone)
 {
     HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::AllowChildFrameContent;
     if (ignorePointerEventsNone)
@@ -159,17 +162,17 @@ static Node* hoveredNodeForPoint(Frame* frame, const IntPoint& point, bool ignor
     return node;
 }
 
-static Node* hoveredNodeForEvent(Frame* frame, const PlatformGestureEvent& event, bool ignorePointerEventsNone)
+static Node* hoveredNodeForEvent(LocalFrame* frame, const PlatformGestureEvent& event, bool ignorePointerEventsNone)
 {
     return hoveredNodeForPoint(frame, event.position(), ignorePointerEventsNone);
 }
 
-static Node* hoveredNodeForEvent(Frame* frame, const PlatformMouseEvent& event, bool ignorePointerEventsNone)
+static Node* hoveredNodeForEvent(LocalFrame* frame, const PlatformMouseEvent& event, bool ignorePointerEventsNone)
 {
     return hoveredNodeForPoint(frame, event.position(), ignorePointerEventsNone);
 }
 
-static Node* hoveredNodeForEvent(Frame* frame, const PlatformTouchEvent& event, bool ignorePointerEventsNone)
+static Node* hoveredNodeForEvent(LocalFrame* frame, const PlatformTouchEvent& event, bool ignorePointerEventsNone)
 {
     const Vector<PlatformTouchPoint>& points = event.touchPoints();
     if (!points.size())
@@ -201,7 +204,7 @@ void RevalidateStyleAttributeTask::scheduleFor(Element* element)
 {
     m_elements.add(element);
     if (!m_timer.isActive())
-        m_timer.startOneShot(0);
+        m_timer.startOneShot(0, FROM_HERE);
 }
 
 void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*)
@@ -218,7 +221,7 @@ void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*)
 String InspectorDOMAgent::toErrorString(ExceptionState& exceptionState)
 {
     if (exceptionState.hadException())
-        return DOMException::getErrorName(exceptionState.code());
+        return DOMException::getErrorName(exceptionState.code()) + " " + exceptionState.message();
     return "";
 }
 
@@ -230,7 +233,6 @@ InspectorDOMAgent::InspectorDOMAgent(InspectorPageAgent* pageAgent, InjectedScri
     , m_frontend(0)
     , m_domListener(0)
     , m_lastNodeId(1)
-    , m_lastBackendNodeId(-1)
     , m_searchingForNode(NotSearching)
     , m_suppressAttributeModifiedEvent(false)
 {
@@ -273,14 +275,14 @@ void InspectorDOMAgent::clearFrontend()
 void InspectorDOMAgent::restore()
 {
     // Reset document to avoid early return from setDocument.
-    m_document = 0;
+    m_document = nullptr;
     setDocument(m_pageAgent->mainFrame()->document());
 }
 
 Vector<Document*> InspectorDOMAgent::documents()
 {
     Vector<Document*> result;
-    for (Frame* frame = m_document->frame(); frame; frame = frame->tree().traverseNext()) {
+    for (LocalFrame* frame = m_document->frame(); frame; frame = frame->tree().traverseNext()) {
         Document* document = frame->document();
         if (!document)
             continue;
@@ -292,8 +294,7 @@ Vector<Document*> InspectorDOMAgent::documents()
 void InspectorDOMAgent::reset()
 {
     discardFrontendBindings();
-    discardBackendBindings();
-    m_document = 0;
+    m_document = nullptr;
 }
 
 void InspectorDOMAgent::setDOMListener(DOMListener* listener)
@@ -360,6 +361,12 @@ void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
             unbind(element->pseudoElement(BEFORE), nodesMap);
         if (element->pseudoElement(AFTER))
             unbind(element->pseudoElement(AFTER), nodesMap);
+
+        if (isHTMLLinkElement(*element)) {
+            HTMLLinkElement& linkElement = toHTMLLinkElement(*element);
+            if (linkElement.isImport() && linkElement.import())
+                unbind(linkElement.import(), nodesMap);
+        }
     }
 
     nodesMap->remove(node);
@@ -376,6 +383,8 @@ void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap)
             child = innerNextSibling(child);
         }
     }
+    if (nodesMap == &m_documentNodeToIdMap)
+        m_cachedChildCount.remove(id);
 }
 
 Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId)
@@ -414,6 +423,20 @@ Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId)
     return toElement(node);
 }
 
+static ShadowRoot* userAgentShadowRoot(Node* node)
+{
+    if (!node || !node->isInShadowTree())
+        return 0;
+
+    Node* candidate = node;
+    while (candidate && !candidate->isShadowRoot())
+        candidate = candidate->parentOrShadowHostNode();
+    ASSERT(candidate);
+    ShadowRoot* shadowRoot = toShadowRoot(candidate);
+
+    return shadowRoot->type() == ShadowRoot::UserAgentShadowRoot ? shadowRoot : 0;
+}
+
 Node* InspectorDOMAgent::assertEditableNode(ErrorString* errorString, int nodeId)
 {
     Node* node = assertNode(errorString, nodeId);
@@ -421,8 +444,14 @@ Node* InspectorDOMAgent::assertEditableNode(ErrorString* errorString, int nodeId
         return 0;
 
     if (node->isInShadowTree()) {
-        *errorString = "Cannot edit nodes from shadow trees";
-        return 0;
+        if (node->isShadowRoot()) {
+            *errorString = "Cannot edit shadow roots";
+            return 0;
+        }
+        if (userAgentShadowRoot(node)) {
+            *errorString = "Cannot edit nodes from user-agent shadow trees";
+            return 0;
+        }
     }
 
     if (node->isPseudoElement()) {
@@ -439,8 +468,8 @@ Element* InspectorDOMAgent::assertEditableElement(ErrorString* errorString, int
     if (!element)
         return 0;
 
-    if (element->isInShadowTree()) {
-        *errorString = "Cannot edit elements from shadow trees";
+    if (element->isInShadowTree() && userAgentShadowRoot(element)) {
+        *errorString = "Cannot edit elements from user-agent shadow trees";
         return 0;
     }
 
@@ -502,29 +531,11 @@ void InspectorDOMAgent::discardFrontendBindings()
     m_idToNode.clear();
     releaseDanglingNodes();
     m_childrenRequested.clear();
+    m_cachedChildCount.clear();
     if (m_revalidateStyleAttrTask)
         m_revalidateStyleAttrTask->reset();
 }
 
-void InspectorDOMAgent::discardBackendBindings()
-{
-    m_backendIdToNode.clear();
-    m_nodeGroupToBackendIdMap.clear();
-}
-
-int InspectorDOMAgent::pushNodeToFrontend(ErrorString* errorString, int documentNodeId, Node* nodeToPush)
-{
-    Document* document = assertDocument(errorString, documentNodeId);
-    if (!document)
-        return 0;
-    if (nodeToPush->document() != document) {
-        *errorString = "Node is not part of the document with given id";
-        return 0;
-    }
-
-    return pushNodePathToFrontend(nodeToPush);
-}
-
 Node* InspectorDOMAgent::nodeForId(int id)
 {
     if (!id)
@@ -643,37 +654,6 @@ int InspectorDOMAgent::boundNodeId(Node* node)
     return m_documentNodeToIdMap.get(node);
 }
 
-BackendNodeId InspectorDOMAgent::backendNodeIdForNode(Node* node, const String& nodeGroup)
-{
-    if (!node)
-        return 0;
-
-    if (!m_nodeGroupToBackendIdMap.contains(nodeGroup))
-        m_nodeGroupToBackendIdMap.set(nodeGroup, NodeToBackendIdMap());
-
-    NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value;
-    BackendNodeId id = map.get(node);
-    if (!id) {
-        id = --m_lastBackendNodeId;
-        map.set(node, id);
-        m_backendIdToNode.set(id, std::make_pair(node, nodeGroup));
-    }
-
-    return id;
-}
-
-void InspectorDOMAgent::releaseBackendNodeIds(ErrorString* errorString, const String& nodeGroup)
-{
-    if (m_nodeGroupToBackendIdMap.contains(nodeGroup)) {
-        NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value;
-        for (NodeToBackendIdMap::iterator it = map.begin(); it != map.end(); ++it)
-            m_backendIdToNode.remove(it->value);
-        m_nodeGroupToBackendIdMap.remove(nodeGroup);
-        return;
-    }
-    *errorString = "Group name not found";
-}
-
 void InspectorDOMAgent::setAttributeValue(ErrorString* errorString, int elementId, const String& name, const String& value)
 {
     Element* element = assertEditableElement(errorString, elementId);
@@ -695,9 +675,9 @@ void InspectorDOMAgent::setAttributesAsText(ErrorString* errorString, int elemen
     bool shouldIgnoreCase = element->document().isHTMLDocument() && element->isHTMLElement();
     // Not all elements can represent the context (i.e. IFRAME), hence using document.body.
     if (shouldIgnoreCase && element->document().body())
-        fragment->parseHTML(markup, element->document().body(), DisallowScriptingContent);
+        fragment->parseHTML(markup, element->document().body(), AllowScriptingContent);
     else
-        fragment->parseXML(markup, 0, DisallowScriptingContent);
+        fragment->parseXML(markup, 0, AllowScriptingContent);
 
     Element* parsedElement = fragment->firstChild() && fragment->firstChild()->isElementNode() ? toElement(fragment->firstChild()) : 0;
     if (!parsedElement) {
@@ -716,12 +696,12 @@ void InspectorDOMAgent::setAttributesAsText(ErrorString* errorString, int elemen
     unsigned numAttrs = parsedElement->attributeCount();
     for (unsigned i = 0; i < numAttrs; ++i) {
         // Add attribute pair
-        const Attribute* attribute = parsedElement->attributeItem(i);
-        String attributeName = attribute->name().toString();
+        const Attribute& attribute = parsedElement->attributeItem(i);
+        String attributeName = attribute.name().toString();
         if (shouldIgnoreCase)
             attributeName = attributeName.lower();
         foundOriginalAttribute |= name && attributeName == caseAdjustedName;
-        if (!m_domEditor->setAttribute(element, attributeName, attribute->value(), errorString))
+        if (!m_domEditor->setAttribute(element, attributeName, attribute.value(), errorString))
             return;
     }
 
@@ -862,8 +842,11 @@ void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int n
         const EventListenerVector& vector = info.eventListenerVector;
         for (size_t j = 0; j < vector.size(); ++j) {
             const RegisteredEventListener& listener = vector[j];
-            if (listener.useCapture)
-                listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.eventTarget->toNode(), objectGroup));
+            if (listener.useCapture) {
+                RefPtr<TypeBuilder::DOM::EventListener> listenerObject = buildObjectForEventListener(listener, info.eventType, info.eventTarget->toNode(), objectGroup);
+                if (listenerObject)
+                    listenersArray->addItem(listenerObject);
+            }
         }
     }
 
@@ -873,8 +856,11 @@ void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int n
         const EventListenerVector& vector = info.eventListenerVector;
         for (size_t j = 0; j < vector.size(); ++j) {
             const RegisteredEventListener& listener = vector[j];
-            if (!listener.useCapture)
-                listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.eventTarget->toNode(), objectGroup));
+            if (!listener.useCapture) {
+                RefPtr<TypeBuilder::DOM::EventListener> listenerObject = buildObjectForEventListener(listener, info.eventType, info.eventTarget->toNode(), objectGroup);
+                if (listenerObject)
+                    listenersArray->addItem(listenerObject);
+            }
         }
     }
 }
@@ -970,14 +956,14 @@ void InspectorDOMAgent::performSearch(ErrorString*, const String& whitespaceTrim
                 unsigned numAttrs = element->attributeCount();
                 for (unsigned i = 0; i < numAttrs; ++i) {
                     // Add attribute pair
-                    const Attribute* attribute = element->attributeItem(i);
-                    if (attribute->localName().find(whitespaceTrimmedQuery, 0, false) != kNotFound) {
+                    const Attribute& attribute = element->attributeItem(i);
+                    if (attribute.localName().find(whitespaceTrimmedQuery, 0, false) != kNotFound) {
                         resultCollector.add(node);
                         break;
                     }
-                    size_t foundPosition = attribute->value().find(attributeQuery, 0, false);
+                    size_t foundPosition = attribute.value().find(attributeQuery, 0, false);
                     if (foundPosition != kNotFound) {
-                        if (!exactAttributeMatch || (!foundPosition && attribute->value().length() == attributeQuery.length())) {
+                        if (!exactAttributeMatch || (!foundPosition && attribute.value().length() == attributeQuery.length())) {
                             resultCollector.add(node);
                             break;
                         }
@@ -993,8 +979,9 @@ void InspectorDOMAgent::performSearch(ErrorString*, const String& whitespaceTrim
         // XPath evaluation
         for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) {
             Document* document = *it;
+            ASSERT(document);
             TrackExceptionState exceptionState;
-            RefPtr<XPathResult> result = DocumentXPathEvaluator::evaluate(document, whitespaceTrimmedQuery, document, 0, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, exceptionState);
+            RefPtrWillBeRawPtr<XPathResult> result = DocumentXPathEvaluator::evaluate(*document, whitespaceTrimmedQuery, document, nullptr, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, exceptionState);
             if (exceptionState.hadException() || !result)
                 continue;
 
@@ -1025,12 +1012,12 @@ void InspectorDOMAgent::performSearch(ErrorString*, const String& whitespaceTrim
     }
 
     *searchId = IdentifiersFactory::createIdentifier();
-    SearchResults::iterator resultsIt = m_searchResults.add(*searchId, Vector<RefPtr<Node> >()).iterator;
+    Vector<RefPtr<Node> >* resultsIt = &m_searchResults.add(*searchId, Vector<RefPtr<Node> >()).storedValue->value;
 
     for (ListHashSet<Node*>::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it)
-        resultsIt->value.append(*it);
+        resultsIt->append(*it);
 
-    *resultCount = resultsIt->value.size();
+    *resultCount = resultsIt->size();
 }
 
 void InspectorDOMAgent::getSearchResults(ErrorString* errorString, const String& searchId, int fromIndex, int toIndex, RefPtr<TypeBuilder::Array<int> >& nodeIds)
@@ -1069,26 +1056,26 @@ bool InspectorDOMAgent::handleMousePress()
     return false;
 }
 
-bool InspectorDOMAgent::handleGestureEvent(Frame* frame, const PlatformGestureEvent& event)
+bool InspectorDOMAgent::handleGestureEvent(LocalFrame* frame, const PlatformGestureEvent& event)
 {
     if (m_searchingForNode == NotSearching || event.type() != PlatformEvent::GestureTap)
         return false;
     Node* node = hoveredNodeForEvent(frame, event, false);
     if (node && m_inspectModeHighlightConfig) {
-        m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig);
+        m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig, false);
         inspect(node);
         return true;
     }
     return false;
 }
 
-bool InspectorDOMAgent::handleTouchEvent(Frame* frame, const PlatformTouchEvent& event)
+bool InspectorDOMAgent::handleTouchEvent(LocalFrame* frame, const PlatformTouchEvent& event)
 {
     if (m_searchingForNode == NotSearching)
         return false;
     Node* node = hoveredNodeForEvent(frame, event, false);
     if (node && m_inspectModeHighlightConfig) {
-        m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig);
+        m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig, false);
         inspect(node);
         return true;
     }
@@ -1101,15 +1088,18 @@ void InspectorDOMAgent::inspect(Node* inspectedNode)
         return;
 
     Node* node = inspectedNode;
-    if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
-        node = node->parentNode();
+    while (node && node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE)
+        node = node->parentOrShadowHostNode();
+
+    if (!node)
+        return;
 
     int nodeId = pushNodePathToFrontend(node);
     if (nodeId)
         m_frontend->inspectNodeRequested(nodeId);
 }
 
-void InspectorDOMAgent::handleMouseMove(Frame* frame, const PlatformMouseEvent& event)
+void InspectorDOMAgent::handleMouseMove(LocalFrame* frame, const PlatformMouseEvent& event)
 {
     if (m_searchingForNode == NotSearching)
         return;
@@ -1118,15 +1108,26 @@ void InspectorDOMAgent::handleMouseMove(Frame* frame, const PlatformMouseEvent&
         return;
     Node* node = hoveredNodeForEvent(frame, event, event.shiftKey());
 
-    while (m_searchingForNode != SearchingForShadow && node && node->isInShadowTree())
+    // Do not highlight within UA shadow root unless requested.
+    if (m_searchingForNode != SearchingForUAShadow) {
+        ShadowRoot* uaShadowRoot = userAgentShadowRoot(node);
+        if (uaShadowRoot)
+            node = uaShadowRoot->host();
+    }
+
+    // Shadow roots don't have boxes - use host element instead.
+    if (node && node->isShadowRoot())
         node = node->parentOrShadowHostNode();
 
+    if (!node)
+        return;
+
     Node* eventTarget = event.shiftKey() ? hoveredNodeForEvent(frame, event, false) : 0;
     if (eventTarget == node)
         eventTarget = 0;
 
     if (node && m_inspectModeHighlightConfig)
-        m_overlay->highlightNode(node, eventTarget, *m_inspectModeHighlightConfig);
+        m_overlay->highlightNode(node, eventTarget, *m_inspectModeHighlightConfig, event.ctrlKey() || event.metaKey());
 }
 
 void InspectorDOMAgent::setSearchingForNode(ErrorString* errorString, SearchMode searchMode, JSONObject* highlightInspectorObject)
@@ -1167,11 +1168,11 @@ PassOwnPtr<HighlightConfig> InspectorDOMAgent::highlightConfigFromInspectorObjec
     return highlightConfig.release();
 }
 
-void InspectorDOMAgent::setInspectModeEnabled(ErrorString* errorString, bool enabled, const bool* inspectShadowDOM, const RefPtr<JSONObject>* highlightConfig)
+void InspectorDOMAgent::setInspectModeEnabled(ErrorString* errorString, bool enabled, const bool* inspectUAShadowDOM, const RefPtr<JSONObject>* highlightConfig)
 {
     if (enabled && !pushDocumentUponHandlelessOperation(errorString))
         return;
-    SearchMode searchMode = enabled ? (inspectShadowDOM && *inspectShadowDOM ? SearchingForShadow : SearchingForNormal) : NotSearching;
+    SearchMode searchMode = enabled ? (inspectUAShadowDOM && *inspectUAShadowDOM ? SearchingForUAShadow : SearchingForNormal) : NotSearching;
     setSearchingForNode(errorString, searchMode, highlightConfig ? highlightConfig->get() : 0);
 }
 
@@ -1219,7 +1220,7 @@ void InspectorDOMAgent::highlightNode(ErrorString* errorString, const RefPtr<JSO
     if (!highlightConfig)
         return;
 
-    m_overlay->highlightNode(node, 0 /* eventTarget */, *highlightConfig);
+    m_overlay->highlightNode(node, 0 /* eventTarget */, *highlightConfig, false);
 }
 
 void InspectorDOMAgent::highlightFrame(
@@ -1228,13 +1229,13 @@ void InspectorDOMAgent::highlightFrame(
     const RefPtr<JSONObject>* color,
     const RefPtr<JSONObject>* outlineColor)
 {
-    Frame* frame = m_pageAgent->frameForId(frameId);
+    LocalFrame* frame = m_pageAgent->frameForId(frameId);
     if (frame && frame->ownerElement()) {
         OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig());
         highlightConfig->showInfo = true; // Always show tooltips for frames.
         highlightConfig->content = parseColor(color);
         highlightConfig->contentOutline = parseColor(outlineColor);
-        m_overlay->highlightNode(frame->ownerElement(), 0 /* eventTarget */, *highlightConfig);
+        m_overlay->highlightNode(frame->ownerElement(), 0 /* eventTarget */, *highlightConfig, false);
     }
 }
 
@@ -1308,12 +1309,12 @@ void InspectorDOMAgent::setFileInputFiles(ErrorString* errorString, int nodeId,
     Node* node = assertNode(errorString, nodeId);
     if (!node)
         return;
-    if (!node->hasTagName(inputTag) || !toHTMLInputElement(node)->isFileUpload()) {
+    if (!isHTMLInputElement(*node) || !toHTMLInputElement(*node).isFileUpload()) {
         *errorString = "Node is not a file input element";
         return;
     }
 
-    RefPtr<FileList> fileList = FileList::create();
+    RefPtrWillBeRawPtr<FileList> fileList = FileList::create();
     for (JSONArray::const_iterator iter = files->begin(); iter != files->end(); ++iter) {
         String path;
         if (!(*iter)->asString(&path)) {
@@ -1353,11 +1354,12 @@ void InspectorDOMAgent::getBoxModel(ErrorString* errorString, int nodeId, RefPtr
     }
 
     RenderObject* renderer = node->renderer();
-    Frame* frame = node->document().frame();
+    LocalFrame* frame = node->document().frame();
     FrameView* view = frame->view();
 
     IntRect boundingBox = pixelSnappedIntRect(view->contentsToRootView(renderer->absoluteBoundingBoxRect()));
     RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0;
+    RefPtr<TypeBuilder::DOM::ShapeOutsideInfo> shapeOutsideInfo = m_overlay->buildObjectForShapeOutside(node);
 
     model = TypeBuilder::DOM::BoxModel::create()
         .setContent(buildArrayForQuad(quads.at(3)))
@@ -1366,6 +1368,8 @@ void InspectorDOMAgent::getBoxModel(ErrorString* errorString, int nodeId, RefPtr
         .setMargin(buildArrayForQuad(quads.at(0)))
         .setWidth(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetWidth(), modelObject) : boundingBox.width())
         .setHeight(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetHeight(), modelObject) : boundingBox.height());
+    if (shapeOutsideInfo)
+        model->setShapeOutside(shapeOutsideInfo);
 }
 
 void InspectorDOMAgent::getNodeForLocation(ErrorString* errorString, int x, int y, int* nodeId)
@@ -1479,9 +1483,11 @@ PassRefPtr<TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* n
     if (node->isElementNode()) {
         Element* element = toElement(node);
         value->setAttributes(buildArrayForElementAttributes(element));
+
         if (node->isFrameOwnerElement()) {
             HTMLFrameOwnerElement* frameOwner = toHTMLFrameOwnerElement(node);
-            if (Frame* frame = frameOwner->contentFrame())
+            LocalFrame* frame = (frameOwner->contentFrame() && frameOwner->contentFrame()->isLocalFrame()) ? toLocalFrame(frameOwner->contentFrame()) : 0;
+            if (frame)
                 value->setFrameId(m_pageAgent->frameId(frame));
             if (Document* doc = frameOwner->contentDocument())
                 value->setContentDocument(buildObjectForNode(doc, 0, nodesMap));
@@ -1496,8 +1502,15 @@ PassRefPtr<TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* n
             forcePushChildren = true;
         }
 
-        if (element->hasTagName(templateTag)) {
-            value->setTemplateContent(buildObjectForNode(toHTMLTemplateElement(element)->content(), 0, nodesMap));
+        if (isHTMLLinkElement(*element)) {
+            HTMLLinkElement& linkElement = toHTMLLinkElement(*element);
+            if (linkElement.isImport() && linkElement.import() && innerParentNode(linkElement.import()) == linkElement)
+                value->setImportedDocument(buildObjectForNode(linkElement.import(), 0, nodesMap));
+            forcePushChildren = true;
+        }
+
+        if (isHTMLTemplateElement(*element)) {
+            value->setTemplateContent(buildObjectForNode(toHTMLTemplateElement(*element).content(), 0, nodesMap));
             forcePushChildren = true;
         }
 
@@ -1538,6 +1551,8 @@ PassRefPtr<TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* n
     if (node->isContainerNode()) {
         int nodeCount = innerChildNodeCount(node);
         value->setChildNodeCount(nodeCount);
+        if (nodesMap == &m_documentNodeToIdMap)
+            m_cachedChildCount.set(id, nodeCount);
         if (forcePushChildren && !depth)
             depth = 1;
         RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodesMap);
@@ -1557,9 +1572,9 @@ PassRefPtr<TypeBuilder::Array<String> > InspectorDOMAgent::buildArrayForElementA
     unsigned numAttrs = element->attributeCount();
     for (unsigned i = 0; i < numAttrs; ++i) {
         // Add attribute pair
-        const Attribute* attribute = element->attributeItem(i);
-        attributesValue->addItem(attribute->name().toString());
-        attributesValue->addItem(attribute->value());
+        const Attribute& attribute = element->attributeItem(i);
+        attributesValue->addItem(attribute.name().toString());
+        attributesValue->addItem(attribute.value());
     }
     return attributesValue.release();
 }
@@ -1591,22 +1606,32 @@ PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > InspectorDOMAgent::build
 PassRefPtr<TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId)
 {
     RefPtr<EventListener> eventListener = registeredEventListener.listener;
+    String sourceName;
+    String scriptId;
+    int lineNumber;
+    if (!eventListenerHandlerLocation(&node->document(), eventListener.get(), sourceName, scriptId, lineNumber))
+        return nullptr;
+
     Document& document = node->document();
+    RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
+        .setScriptId(scriptId)
+        .setLineNumber(lineNumber);
     RefPtr<TypeBuilder::DOM::EventListener> value = TypeBuilder::DOM::EventListener::create()
         .setType(eventType)
         .setUseCapture(registeredEventListener.useCapture)
         .setIsAttribute(eventListener->isAttribute())
         .setNodeId(pushNodePathToFrontend(node))
-        .setHandlerBody(eventListenerHandlerBody(&document, eventListener.get()));
+        .setHandlerBody(eventListenerHandlerBody(&document, eventListener.get()))
+        .setLocation(location);
     if (objectGroupId) {
         ScriptValue functionValue = eventListenerHandler(&document, eventListener.get());
-        if (!functionValue.hasNoValue()) {
-            Frame* frame = document.frame();
+        if (!functionValue.isEmpty()) {
+            LocalFrame* frame = document.frame();
             if (frame) {
                 ScriptState* scriptState = eventListenerHandlerScriptState(frame, eventListener.get());
                 if (scriptState) {
                     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
-                    if (!injectedScript.hasNoValue()) {
+                    if (!injectedScript.isEmpty()) {
                         RefPtr<TypeBuilder::Runtime::RemoteObject> valueJson = injectedScript.wrapObject(functionValue, *objectGroupId);
                         value->setHandler(valueJson);
                     }
@@ -1614,24 +1639,15 @@ PassRefPtr<TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildObjectForEve
             }
         }
     }
-    String sourceName;
-    String scriptId;
-    int lineNumber;
-    if (eventListenerHandlerLocation(&node->document(), eventListener.get(), sourceName, scriptId, lineNumber)) {
-        RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
-            .setScriptId(scriptId)
-            .setLineNumber(lineNumber);
-        value->setLocation(location);
-        if (!sourceName.isEmpty())
-            value->setSourceName(sourceName);
-    }
+    if (!sourceName.isEmpty())
+        value->setSourceName(sourceName);
     return value.release();
 }
 
 PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > InspectorDOMAgent::buildArrayForPseudoElements(Element* element, NodeToIdMap* nodesMap)
 {
     if (!element->pseudoElement(BEFORE) && !element->pseudoElement(AFTER))
-        return 0;
+        return nullptr;
 
     RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > pseudoElements = TypeBuilder::Array<TypeBuilder::DOM::Node>::create();
     if (element->pseudoElement(BEFORE))
@@ -1680,6 +1696,8 @@ Node* InspectorDOMAgent::innerParentNode(Node* node)
 {
     if (node->isDocumentNode()) {
         Document* document = toDocument(node);
+        if (HTMLImportLoader* loader = document->importLoader())
+            return loader->firstImport()->link();
         return document->ownerElement();
     }
     return node->parentOrShadowHostNode();
@@ -1691,7 +1709,7 @@ bool InspectorDOMAgent::isWhitespace(Node* node)
     return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0;
 }
 
-void InspectorDOMAgent::domContentLoadedEventFired(Frame* frame)
+void InspectorDOMAgent::domContentLoadedEventFired(LocalFrame* frame)
 {
     if (!frame->isMainFrame())
         return;
@@ -1702,7 +1720,7 @@ void InspectorDOMAgent::domContentLoadedEventFired(Frame* frame)
         m_frontend->documentUpdated();
 }
 
-void InspectorDOMAgent::invalidateFrameOwnerElement(Frame* frame)
+void InspectorDOMAgent::invalidateFrameOwnerElement(LocalFrame* frame)
 {
     Element* frameOwner = frame->document()->ownerElement();
     if (!frameOwner)
@@ -1723,12 +1741,12 @@ void InspectorDOMAgent::invalidateFrameOwnerElement(Frame* frame)
     m_frontend->childNodeInserted(parentId, prevId, value.release());
 }
 
-void InspectorDOMAgent::didCommitLoad(Frame* frame, DocumentLoader* loader)
+void InspectorDOMAgent::didCommitLoad(LocalFrame* frame, DocumentLoader* loader)
 {
     // FIXME: If "frame" is always guarenteed to be in the same Page as loader->frame()
     // then all we need to check here is loader->frame()->isMainFrame()
     // and we don't need "frame" at all.
-    Frame* mainFrame = frame->page()->mainFrame();
+    LocalFrame* mainFrame = frame->page()->mainFrame();
     if (loader->frame() != mainFrame) {
         invalidateFrameOwnerElement(loader->frame());
         return;
@@ -1748,15 +1766,16 @@ void InspectorDOMAgent::didInsertDOMNode(Node* node)
     ContainerNode* parent = node->parentNode();
     if (!parent)
         return;
-
     int parentId = m_documentNodeToIdMap.get(parent);
     // Return if parent is not mapped yet.
     if (!parentId)
         return;
 
     if (!m_childrenRequested.contains(parentId)) {
-        // No children are mapped yet -> only notify on changes of hasChildren.
-        m_frontend->childNodeCountUpdated(parentId, innerChildNodeCount(parent));
+        // No children are mapped yet -> only notify on changes of child count.
+        int count = m_cachedChildCount.get(parentId) + 1;
+        m_cachedChildCount.set(parentId, count);
+        m_frontend->childNodeCountUpdated(parentId, count);
     } else {
         // Children have been requested -> return value of a new child.
         Node* prevSibling = innerPreviousSibling(node);
@@ -1780,11 +1799,13 @@ void InspectorDOMAgent::willRemoveDOMNode(Node* node)
     int parentId = m_documentNodeToIdMap.get(parent);
 
     if (!m_childrenRequested.contains(parentId)) {
-        // No children are mapped yet -> only notify on changes of hasChildren.
-        if (innerChildNodeCount(parent) == 1)
-            m_frontend->childNodeCountUpdated(parentId, 0);
-    } else
+        // No children are mapped yet -> only notify on changes of child count.
+        int count = m_cachedChildCount.get(parentId) - 1;
+        m_cachedChildCount.set(parentId, count);
+        m_frontend->childNodeCountUpdated(parentId, count);
+    } else {
         m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node));
+    }
     unbind(node, &m_documentNodeToIdMap);
 }
 
@@ -1888,7 +1909,7 @@ void InspectorDOMAgent::willPopShadowRoot(Element* host, ShadowRoot* root)
         m_frontend->shadowRootPopped(hostId, rootId);
 }
 
-void InspectorDOMAgent::frameDocumentUpdated(Frame* frame)
+void InspectorDOMAgent::frameDocumentUpdated(LocalFrame* frame)
 {
     Document* document = frame->document();
     if (!document)
@@ -1933,9 +1954,22 @@ void InspectorDOMAgent::pseudoElementDestroyed(PseudoElement* pseudoElement)
     m_frontend->pseudoElementRemoved(parentId, pseudoElementId);
 }
 
+static ShadowRoot* shadowRootForNode(Node* node, const String& type)
+{
+    if (!node->isElementNode())
+        return 0;
+    if (type == "a")
+        return toElement(node)->shadowRoot();
+    if (type == "u")
+        return toElement(node)->userAgentShadowRoot();
+    return 0;
+}
+
 Node* InspectorDOMAgent::nodeForPath(const String& path)
 {
-    // The path is of form "1,HTML,2,BODY,1,DIV"
+    // The path is of form "1,HTML,2,BODY,1,DIV" (<index> and <nodeName> interleaved).
+    // <index> may also be "a" (author shadow root) or "u" (user-agent shadow root),
+    // in which case <nodeName> MUST be "#document-fragment".
     if (!m_document)
         return 0;
 
@@ -1946,13 +1980,17 @@ Node* InspectorDOMAgent::nodeForPath(const String& path)
         return 0;
     for (size_t i = 0; i < pathTokens.size() - 1; i += 2) {
         bool success = true;
-        unsigned childNumber = pathTokens[i].toUInt(&success);
-        if (!success)
-            return 0;
-        if (childNumber >= innerChildNodeCount(node))
-            return 0;
+        String& indexValue = pathTokens[i];
+        unsigned childNumber = indexValue.toUInt(&success);
+        Node* child;
+        if (!success) {
+            child = shadowRootForNode(node, indexValue);
+        } else {
+            if (childNumber >= innerChildNodeCount(node))
+                return 0;
 
-        Node* child = innerFirstChild(node);
+            child = innerFirstChild(node);
+        }
         String childName = pathTokens[i + 1];
         for (size_t j = 0; child && j < childNumber; ++j)
             child = innerNextSibling(child);
@@ -1972,20 +2010,22 @@ void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString* errorString, const
         *errorString = "No node with given path found";
 }
 
-void InspectorDOMAgent::pushNodeByBackendIdToFrontend(ErrorString* errorString, BackendNodeId backendNodeId, int* nodeId)
+void InspectorDOMAgent::pushNodesByBackendIdsToFrontend(ErrorString* errorString, const RefPtr<JSONArray>& backendNodeIds, RefPtr<TypeBuilder::Array<int> >& result)
 {
-    if (!m_backendIdToNode.contains(backendNodeId)) {
-        *errorString = "No node with given backend id found";
-        return;
-    }
+    result = TypeBuilder::Array<int>::create();
+    for (JSONArray::const_iterator it = backendNodeIds->begin(); it != backendNodeIds->end(); ++it) {
+        int backendNodeId;
 
-    Node* node = m_backendIdToNode.get(backendNodeId).first;
-    String nodeGroup = m_backendIdToNode.get(backendNodeId).second;
-    *nodeId = pushNodePathToFrontend(node);
+        if (!(*it)->asNumber(&backendNodeId)) {
+            *errorString = "Invalid argument type";
+            return;
+        }
 
-    if (nodeGroup == "") {
-        m_backendIdToNode.remove(backendNodeId);
-        m_nodeGroupToBackendIdMap.find(nodeGroup)->value.remove(node);
+        Node* node = InspectorNodeIds::nodeForId(backendNodeId);
+        if (node && node->document().page() == m_pageAgent->page())
+            result->addItem(pushNodePathToFrontend(node));
+        else
+            result->addItem(0);
     }
 }
 
@@ -1999,7 +2039,7 @@ void InspectorDOMAgent::getRelayoutBoundary(ErrorString* errorString, int nodeId
         *errorString = "No renderer for node, perhaps orphan or hidden node";
         return;
     }
-    while (renderer && !renderer->isRoot() && !renderer->isRelayoutBoundaryForInspector())
+    while (renderer && !renderer->isDocumentElement() && !renderer->isRelayoutBoundaryForInspector())
         renderer = renderer->container();
     Node* resultNode = renderer ? renderer->generatingNode() : node->ownerDocument();
     *relayoutBoundaryNodeId = pushNodePathToFrontend(resultNode);
@@ -2008,13 +2048,13 @@ void InspectorDOMAgent::getRelayoutBoundary(ErrorString* errorString, int nodeId
 PassRefPtr<TypeBuilder::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup)
 {
     Document* document = node->isDocumentNode() ? &node->document() : node->ownerDocument();
-    Frame* frame = document ? document->frame() : 0;
+    LocalFrame* frame = document ? document->frame() : 0;
     if (!frame)
-        return 0;
+        return nullptr;
 
-    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame));
-    if (injectedScript.hasNoValue())
-        return 0;
+    InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(ScriptState::forMainWorld(frame));
+    if (injectedScript.isEmpty())
+        return nullptr;
 
     return injectedScript.wrapNode(node, objectGroup);
 }