1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2011 Google Inc. All rights reserved. 4 * Copyright (C) 2009 Joseph Pecoraro 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 16 * its contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "core/inspector/InspectorDOMAgent.h" 33 34 #include "HTMLNames.h" 35 #include "InspectorFrontend.h" 36 #include "bindings/v8/ExceptionState.h" 37 #include "bindings/v8/ScriptEventListener.h" 38 #include "core/dom/Attr.h" 39 #include "core/dom/CharacterData.h" 40 #include "core/dom/ContainerNode.h" 41 #include "core/dom/DOMException.h" 42 #include "core/dom/Document.h" 43 #include "core/dom/DocumentFragment.h" 44 #include "core/dom/DocumentType.h" 45 #include "core/dom/Element.h" 46 #include "core/dom/EventListener.h" 47 #include "core/dom/EventTarget.h" 48 #include "core/dom/Node.h" 49 #include "core/dom/NodeList.h" 50 #include "core/dom/NodeTraversal.h" 51 #include "core/dom/Text.h" 52 #include "core/dom/shadow/ElementShadow.h" 53 #include "core/dom/shadow/ShadowRoot.h" 54 #include "core/editing/markup.h" 55 #include "core/fileapi/File.h" 56 #include "core/fileapi/FileList.h" 57 #include "core/html/HTMLFrameOwnerElement.h" 58 #include "core/html/HTMLInputElement.h" 59 #include "core/html/HTMLTemplateElement.h" 60 #include "core/inspector/DOMEditor.h" 61 #include "core/inspector/DOMPatchSupport.h" 62 #include "core/inspector/IdentifiersFactory.h" 63 #include "core/inspector/InjectedScriptManager.h" 64 #include "core/inspector/InspectorHistory.h" 65 #include "core/inspector/InspectorOverlay.h" 66 #include "core/inspector/InspectorPageAgent.h" 67 #include "core/inspector/InspectorState.h" 68 #include "core/inspector/InstrumentingAgents.h" 69 #include "core/loader/DocumentLoader.h" 70 #include "core/page/Frame.h" 71 #include "core/page/FrameTree.h" 72 #include "core/page/Page.h" 73 #include "core/platform/PlatformGestureEvent.h" 74 #include "core/platform/PlatformMouseEvent.h" 75 #include "core/platform/PlatformTouchEvent.h" 76 #include "core/rendering/HitTestResult.h" 77 #include "core/rendering/RenderView.h" 78 #include "core/xml/DocumentXPathEvaluator.h" 79 #include "core/xml/XPathResult.h" 80 #include "wtf/HashSet.h" 81 #include "wtf/ListHashSet.h" 82 #include "wtf/OwnPtr.h" 83 #include "wtf/Vector.h" 84 #include "wtf/text/CString.h" 85 #include "wtf/text/WTFString.h" 86 87 namespace WebCore { 88 89 using namespace HTMLNames; 90 91 namespace DOMAgentState { 92 static const char documentRequested[] = "documentRequested"; 93 }; 94 95 static const size_t maxTextSize = 10000; 96 static const UChar ellipsisUChar[] = { 0x2026, 0 }; 97 98 static Color parseColor(const RefPtr<JSONObject>* colorObject) 99 { 100 if (!colorObject || !(*colorObject)) 101 return Color::transparent; 102 103 int r; 104 int g; 105 int b; 106 bool success = (*colorObject)->getNumber("r", &r); 107 success |= (*colorObject)->getNumber("g", &g); 108 success |= (*colorObject)->getNumber("b", &b); 109 if (!success) 110 return Color::transparent; 111 112 double a; 113 success = (*colorObject)->getNumber("a", &a); 114 if (!success) 115 return Color(r, g, b); 116 117 // Clamp alpha to the [0..1] range. 118 if (a < 0) 119 a = 0; 120 else if (a > 1) 121 a = 1; 122 123 return Color(r, g, b, static_cast<int>(a * 255)); 124 } 125 126 static Color parseConfigColor(const String& fieldName, JSONObject* configObject) 127 { 128 const RefPtr<JSONObject> colorObject = configObject->getObject(fieldName); 129 return parseColor(&colorObject); 130 } 131 132 static bool parseQuad(const RefPtr<JSONArray>& quadArray, FloatQuad* quad) 133 { 134 if (!quadArray) 135 return false; 136 const size_t coordinatesInQuad = 8; 137 double coordinates[coordinatesInQuad]; 138 if (quadArray->length() != coordinatesInQuad) 139 return false; 140 for (size_t i = 0; i < coordinatesInQuad; ++i) { 141 if (!quadArray->get(i)->asNumber(coordinates + i)) 142 return false; 143 } 144 quad->setP1(FloatPoint(coordinates[0], coordinates[1])); 145 quad->setP2(FloatPoint(coordinates[2], coordinates[3])); 146 quad->setP3(FloatPoint(coordinates[4], coordinates[5])); 147 quad->setP4(FloatPoint(coordinates[6], coordinates[7])); 148 149 return true; 150 } 151 152 static Node* hoveredNodeForPoint(Frame* frame, const IntPoint& point, bool ignorePointerEventsNone) 153 { 154 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::AllowChildFrameContent; 155 if (ignorePointerEventsNone) 156 hitType |= HitTestRequest::IgnorePointerEventsNone; 157 HitTestRequest request(hitType); 158 HitTestResult result(frame->view()->windowToContents(point)); 159 frame->contentRenderer()->hitTest(request, result); 160 Node* node = result.innerNode(); 161 while (node && node->nodeType() == Node::TEXT_NODE) 162 node = node->parentNode(); 163 return node; 164 } 165 166 static Node* hoveredNodeForEvent(Frame* frame, const PlatformGestureEvent& event, bool ignorePointerEventsNone) 167 { 168 return hoveredNodeForPoint(frame, event.position(), ignorePointerEventsNone); 169 } 170 171 static Node* hoveredNodeForEvent(Frame* frame, const PlatformMouseEvent& event, bool ignorePointerEventsNone) 172 { 173 return hoveredNodeForPoint(frame, event.position(), ignorePointerEventsNone); 174 } 175 176 static Node* hoveredNodeForEvent(Frame* frame, const PlatformTouchEvent& event, bool ignorePointerEventsNone) 177 { 178 const Vector<PlatformTouchPoint>& points = event.touchPoints(); 179 if (!points.size()) 180 return 0; 181 return hoveredNodeForPoint(frame, points[0].pos(), ignorePointerEventsNone); 182 } 183 184 class RevalidateStyleAttributeTask { 185 WTF_MAKE_FAST_ALLOCATED; 186 public: 187 RevalidateStyleAttributeTask(InspectorDOMAgent*); 188 void scheduleFor(Element*); 189 void reset() { m_timer.stop(); } 190 void onTimer(Timer<RevalidateStyleAttributeTask>*); 191 192 private: 193 InspectorDOMAgent* m_domAgent; 194 Timer<RevalidateStyleAttributeTask> m_timer; 195 HashSet<RefPtr<Element> > m_elements; 196 }; 197 198 RevalidateStyleAttributeTask::RevalidateStyleAttributeTask(InspectorDOMAgent* domAgent) 199 : m_domAgent(domAgent) 200 , m_timer(this, &RevalidateStyleAttributeTask::onTimer) 201 { 202 } 203 204 void RevalidateStyleAttributeTask::scheduleFor(Element* element) 205 { 206 m_elements.add(element); 207 if (!m_timer.isActive()) 208 m_timer.startOneShot(0); 209 } 210 211 void RevalidateStyleAttributeTask::onTimer(Timer<RevalidateStyleAttributeTask>*) 212 { 213 // The timer is stopped on m_domAgent destruction, so this method will never be called after m_domAgent has been destroyed. 214 Vector<Element*> elements; 215 for (HashSet<RefPtr<Element> >::iterator it = m_elements.begin(), end = m_elements.end(); it != end; ++it) 216 elements.append(it->get()); 217 m_domAgent->styleAttributeInvalidated(elements); 218 219 m_elements.clear(); 220 } 221 222 String InspectorDOMAgent::toErrorString(ExceptionState& es) 223 { 224 if (es.hadException()) 225 return DOMException::getErrorName(es.code()); 226 return ""; 227 } 228 229 InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager, InspectorOverlay* overlay, InspectorClient* client) 230 : InspectorBaseAgent<InspectorDOMAgent>("DOM", instrumentingAgents, inspectorState) 231 , m_pageAgent(pageAgent) 232 , m_injectedScriptManager(injectedScriptManager) 233 , m_overlay(overlay) 234 , m_client(client) 235 , m_frontend(0) 236 , m_domListener(0) 237 , m_lastNodeId(1) 238 , m_lastBackendNodeId(-1) 239 , m_searchingForNode(NotSearching) 240 , m_suppressAttributeModifiedEvent(false) 241 { 242 } 243 244 InspectorDOMAgent::~InspectorDOMAgent() 245 { 246 reset(); 247 ASSERT(m_searchingForNode == NotSearching); 248 } 249 250 void InspectorDOMAgent::setFrontend(InspectorFrontend* frontend) 251 { 252 ASSERT(!m_frontend); 253 m_history = adoptPtr(new InspectorHistory()); 254 m_domEditor = adoptPtr(new DOMEditor(m_history.get())); 255 256 m_frontend = frontend->dom(); 257 m_instrumentingAgents->setInspectorDOMAgent(this); 258 m_document = m_pageAgent->mainFrame()->document(); 259 } 260 261 void InspectorDOMAgent::clearFrontend() 262 { 263 ASSERT(m_frontend); 264 265 m_history.clear(); 266 m_domEditor.clear(); 267 268 ErrorString error; 269 setSearchingForNode(&error, NotSearching, 0); 270 hideHighlight(&error); 271 272 m_frontend = 0; 273 m_instrumentingAgents->setInspectorDOMAgent(0); 274 m_state->setBoolean(DOMAgentState::documentRequested, false); 275 reset(); 276 } 277 278 void InspectorDOMAgent::restore() 279 { 280 // Reset document to avoid early return from setDocument. 281 m_document = 0; 282 setDocument(m_pageAgent->mainFrame()->document()); 283 } 284 285 Vector<Document*> InspectorDOMAgent::documents() 286 { 287 Vector<Document*> result; 288 for (Frame* frame = m_document->frame(); frame; frame = frame->tree()->traverseNext()) { 289 Document* document = frame->document(); 290 if (!document) 291 continue; 292 result.append(document); 293 } 294 return result; 295 } 296 297 void InspectorDOMAgent::reset() 298 { 299 discardFrontendBindings(); 300 discardBackendBindings(); 301 m_document = 0; 302 } 303 304 void InspectorDOMAgent::setDOMListener(DOMListener* listener) 305 { 306 m_domListener = listener; 307 } 308 309 void InspectorDOMAgent::setDocument(Document* doc) 310 { 311 if (doc == m_document.get()) 312 return; 313 314 reset(); 315 316 m_document = doc; 317 318 if (!m_state->getBoolean(DOMAgentState::documentRequested)) 319 return; 320 321 // Immediately communicate 0 document or document that has finished loading. 322 if (!doc || !doc->parsing()) 323 m_frontend->documentUpdated(); 324 } 325 326 void InspectorDOMAgent::releaseDanglingNodes() 327 { 328 m_danglingNodeToIdMaps.clear(); 329 } 330 331 int InspectorDOMAgent::bind(Node* node, NodeToIdMap* nodesMap) 332 { 333 int id = nodesMap->get(node); 334 if (id) 335 return id; 336 id = m_lastNodeId++; 337 nodesMap->set(node, id); 338 m_idToNode.set(id, node); 339 m_idToNodesMap.set(id, nodesMap); 340 return id; 341 } 342 343 void InspectorDOMAgent::unbind(Node* node, NodeToIdMap* nodesMap) 344 { 345 int id = nodesMap->get(node); 346 if (!id) 347 return; 348 349 m_idToNode.remove(id); 350 351 if (node->isFrameOwnerElement()) { 352 const HTMLFrameOwnerElement* frameOwner = static_cast<const HTMLFrameOwnerElement*>(node); 353 Document* contentDocument = frameOwner->contentDocument(); 354 if (m_domListener) 355 m_domListener->didRemoveDocument(contentDocument); 356 if (contentDocument) 357 unbind(contentDocument, nodesMap); 358 } 359 360 for (ShadowRoot* root = node->youngestShadowRoot(); root; root = root->olderShadowRoot()) 361 unbind(root, nodesMap); 362 363 nodesMap->remove(node); 364 if (m_domListener) 365 m_domListener->didRemoveDOMNode(node); 366 367 bool childrenRequested = m_childrenRequested.contains(id); 368 if (childrenRequested) { 369 // Unbind subtree known to client recursively. 370 m_childrenRequested.remove(id); 371 Node* child = innerFirstChild(node); 372 while (child) { 373 unbind(child, nodesMap); 374 child = innerNextSibling(child); 375 } 376 } 377 } 378 379 Node* InspectorDOMAgent::assertNode(ErrorString* errorString, int nodeId) 380 { 381 Node* node = nodeForId(nodeId); 382 if (!node) { 383 *errorString = "Could not find node with given id"; 384 return 0; 385 } 386 return node; 387 } 388 389 Document* InspectorDOMAgent::assertDocument(ErrorString* errorString, int nodeId) 390 { 391 Node* node = assertNode(errorString, nodeId); 392 if (!node) 393 return 0; 394 395 if (!(node->isDocumentNode())) { 396 *errorString = "Document is not available"; 397 return 0; 398 } 399 return toDocument(node); 400 } 401 402 Element* InspectorDOMAgent::assertElement(ErrorString* errorString, int nodeId) 403 { 404 Node* node = assertNode(errorString, nodeId); 405 if (!node) 406 return 0; 407 408 if (node->nodeType() != Node::ELEMENT_NODE) { 409 *errorString = "Node is not an Element"; 410 return 0; 411 } 412 return toElement(node); 413 } 414 415 Node* InspectorDOMAgent::assertEditableNode(ErrorString* errorString, int nodeId) 416 { 417 Node* node = assertNode(errorString, nodeId); 418 if (!node) 419 return 0; 420 421 if (node->isInShadowTree()) { 422 *errorString = "Can not edit nodes from shadow trees"; 423 return 0; 424 } 425 426 return node; 427 } 428 429 Element* InspectorDOMAgent::assertEditableElement(ErrorString* errorString, int nodeId) 430 { 431 Element* element = assertElement(errorString, nodeId); 432 if (!element) 433 return 0; 434 435 if (element->isInShadowTree()) { 436 *errorString = "Can not edit elements from shadow trees"; 437 return 0; 438 } 439 return element; 440 } 441 442 void InspectorDOMAgent::getDocument(ErrorString* errorString, RefPtr<TypeBuilder::DOM::Node>& root) 443 { 444 m_state->setBoolean(DOMAgentState::documentRequested, true); 445 446 if (!m_document) { 447 *errorString = "Document is not available"; 448 return; 449 } 450 451 discardFrontendBindings(); 452 453 root = buildObjectForNode(m_document.get(), 2, &m_documentNodeToIdMap); 454 } 455 456 void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId, int depth) 457 { 458 Node* node = nodeForId(nodeId); 459 if (!node || (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE && node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE)) 460 return; 461 462 NodeToIdMap* nodeMap = m_idToNodesMap.get(nodeId); 463 464 if (m_childrenRequested.contains(nodeId)) { 465 if (depth <= 1) 466 return; 467 468 depth--; 469 470 for (node = innerFirstChild(node); node; node = innerNextSibling(node)) { 471 int childNodeId = nodeMap->get(node); 472 ASSERT(childNodeId); 473 pushChildNodesToFrontend(childNodeId, depth); 474 } 475 476 return; 477 } 478 479 RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodeMap); 480 m_frontend->setChildNodes(nodeId, children.release()); 481 } 482 483 void InspectorDOMAgent::discardFrontendBindings() 484 { 485 if (m_history) 486 m_history->reset(); 487 m_searchResults.clear(); 488 m_documentNodeToIdMap.clear(); 489 m_idToNode.clear(); 490 releaseDanglingNodes(); 491 m_childrenRequested.clear(); 492 if (m_revalidateStyleAttrTask) 493 m_revalidateStyleAttrTask->reset(); 494 } 495 496 void InspectorDOMAgent::discardBackendBindings() 497 { 498 m_backendIdToNode.clear(); 499 m_nodeGroupToBackendIdMap.clear(); 500 } 501 502 int InspectorDOMAgent::pushNodeToFrontend(ErrorString* errorString, int documentNodeId, Node* nodeToPush) 503 { 504 Document* document = assertDocument(errorString, documentNodeId); 505 if (!document) 506 return 0; 507 if (nodeToPush->document() != document) { 508 *errorString = "Node is not part of the document with given id"; 509 return 0; 510 } 511 512 return pushNodePathToFrontend(nodeToPush); 513 } 514 515 Node* InspectorDOMAgent::nodeForId(int id) 516 { 517 if (!id) 518 return 0; 519 520 HashMap<int, Node*>::iterator it = m_idToNode.find(id); 521 if (it != m_idToNode.end()) 522 return it->value; 523 return 0; 524 } 525 526 void InspectorDOMAgent::requestChildNodes(ErrorString* errorString, int nodeId, const int* depth) 527 { 528 int sanitizedDepth; 529 530 if (!depth) 531 sanitizedDepth = 1; 532 else if (*depth == -1) 533 sanitizedDepth = INT_MAX; 534 else if (*depth > 0) 535 sanitizedDepth = *depth; 536 else { 537 *errorString = "Please provide a positive integer as a depth or -1 for entire subtree"; 538 return; 539 } 540 541 pushChildNodesToFrontend(nodeId, sanitizedDepth); 542 } 543 544 void InspectorDOMAgent::querySelector(ErrorString* errorString, int nodeId, const String& selectors, int* elementId) 545 { 546 *elementId = 0; 547 Node* node = assertNode(errorString, nodeId); 548 if (!node) 549 return; 550 551 TrackExceptionState es; 552 RefPtr<Element> element = node->querySelector(selectors, es); 553 if (es.hadException()) { 554 *errorString = "DOM Error while querying"; 555 return; 556 } 557 558 if (element) 559 *elementId = pushNodePathToFrontend(element.get()); 560 } 561 562 void InspectorDOMAgent::querySelectorAll(ErrorString* errorString, int nodeId, const String& selectors, RefPtr<TypeBuilder::Array<int> >& result) 563 { 564 Node* node = assertNode(errorString, nodeId); 565 if (!node) 566 return; 567 568 TrackExceptionState es; 569 RefPtr<NodeList> nodes = node->querySelectorAll(selectors, es); 570 if (es.hadException()) { 571 *errorString = "DOM Error while querying"; 572 return; 573 } 574 575 result = TypeBuilder::Array<int>::create(); 576 577 for (unsigned i = 0; i < nodes->length(); ++i) 578 result->addItem(pushNodePathToFrontend(nodes->item(i))); 579 } 580 581 int InspectorDOMAgent::pushNodePathToFrontend(Node* nodeToPush) 582 { 583 ASSERT(nodeToPush); // Invalid input 584 585 if (!m_document) 586 return 0; 587 if (!m_documentNodeToIdMap.contains(m_document)) 588 return 0; 589 590 // Return id in case the node is known. 591 int result = m_documentNodeToIdMap.get(nodeToPush); 592 if (result) 593 return result; 594 595 Node* node = nodeToPush; 596 Vector<Node*> path; 597 NodeToIdMap* danglingMap = 0; 598 599 while (true) { 600 Node* parent = innerParentNode(node); 601 if (!parent) { 602 // Node being pushed is detached -> push subtree root. 603 OwnPtr<NodeToIdMap> newMap = adoptPtr(new NodeToIdMap); 604 danglingMap = newMap.get(); 605 m_danglingNodeToIdMaps.append(newMap.release()); 606 RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = TypeBuilder::Array<TypeBuilder::DOM::Node>::create(); 607 children->addItem(buildObjectForNode(node, 0, danglingMap)); 608 m_frontend->setChildNodes(0, children); 609 break; 610 } else { 611 path.append(parent); 612 if (m_documentNodeToIdMap.get(parent)) 613 break; 614 else 615 node = parent; 616 } 617 } 618 619 NodeToIdMap* map = danglingMap ? danglingMap : &m_documentNodeToIdMap; 620 for (int i = path.size() - 1; i >= 0; --i) { 621 int nodeId = map->get(path.at(i)); 622 ASSERT(nodeId); 623 pushChildNodesToFrontend(nodeId); 624 } 625 return map->get(nodeToPush); 626 } 627 628 int InspectorDOMAgent::boundNodeId(Node* node) 629 { 630 return m_documentNodeToIdMap.get(node); 631 } 632 633 BackendNodeId InspectorDOMAgent::backendNodeIdForNode(Node* node, const String& nodeGroup) 634 { 635 if (!node) 636 return 0; 637 638 if (!m_nodeGroupToBackendIdMap.contains(nodeGroup)) 639 m_nodeGroupToBackendIdMap.set(nodeGroup, NodeToBackendIdMap()); 640 641 NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value; 642 BackendNodeId id = map.get(node); 643 if (!id) { 644 id = --m_lastBackendNodeId; 645 map.set(node, id); 646 m_backendIdToNode.set(id, std::make_pair(node, nodeGroup)); 647 } 648 649 return id; 650 } 651 652 void InspectorDOMAgent::releaseBackendNodeIds(ErrorString* errorString, const String& nodeGroup) 653 { 654 if (m_nodeGroupToBackendIdMap.contains(nodeGroup)) { 655 NodeToBackendIdMap& map = m_nodeGroupToBackendIdMap.find(nodeGroup)->value; 656 for (NodeToBackendIdMap::iterator it = map.begin(); it != map.end(); ++it) 657 m_backendIdToNode.remove(it->value); 658 m_nodeGroupToBackendIdMap.remove(nodeGroup); 659 return; 660 } 661 *errorString = "Group name not found"; 662 } 663 664 void InspectorDOMAgent::setAttributeValue(ErrorString* errorString, int elementId, const String& name, const String& value) 665 { 666 Element* element = assertEditableElement(errorString, elementId); 667 if (!element) 668 return; 669 670 m_domEditor->setAttribute(element, name, value, errorString); 671 } 672 673 void InspectorDOMAgent::setAttributesAsText(ErrorString* errorString, int elementId, const String& text, const String* const name) 674 { 675 Element* element = assertEditableElement(errorString, elementId); 676 if (!element) 677 return; 678 679 String markup = "<span " + text + "></span>"; 680 RefPtr<DocumentFragment> fragment = element->document()->createDocumentFragment(); 681 682 bool shouldIgnoreCase = element->document()->isHTMLDocument() && element->isHTMLElement(); 683 // Not all elements can represent the context (i.e. IFRAME), hence using document.body. 684 if (shouldIgnoreCase && element->document()->body()) 685 fragment->parseHTML(markup, element->document()->body(), DisallowScriptingContent); 686 else 687 fragment->parseXML(markup, 0, DisallowScriptingContent); 688 689 Element* parsedElement = fragment->firstChild() && fragment->firstChild()->isElementNode() ? toElement(fragment->firstChild()) : 0; 690 if (!parsedElement) { 691 *errorString = "Could not parse value as attributes"; 692 return; 693 } 694 695 String caseAdjustedName = name ? (shouldIgnoreCase ? name->lower() : *name) : String(); 696 697 if (!parsedElement->hasAttributes() && name) { 698 m_domEditor->removeAttribute(element, caseAdjustedName, errorString); 699 return; 700 } 701 702 bool foundOriginalAttribute = false; 703 unsigned numAttrs = parsedElement->attributeCount(); 704 for (unsigned i = 0; i < numAttrs; ++i) { 705 // Add attribute pair 706 const Attribute* attribute = parsedElement->attributeItem(i); 707 String attributeName = attribute->name().toString(); 708 if (shouldIgnoreCase) 709 attributeName = attributeName.lower(); 710 foundOriginalAttribute |= name && attributeName == caseAdjustedName; 711 if (!m_domEditor->setAttribute(element, attributeName, attribute->value(), errorString)) 712 return; 713 } 714 715 if (!foundOriginalAttribute && name && !name->stripWhiteSpace().isEmpty()) 716 m_domEditor->removeAttribute(element, caseAdjustedName, errorString); 717 } 718 719 void InspectorDOMAgent::removeAttribute(ErrorString* errorString, int elementId, const String& name) 720 { 721 Element* element = assertEditableElement(errorString, elementId); 722 if (!element) 723 return; 724 725 m_domEditor->removeAttribute(element, name, errorString); 726 } 727 728 void InspectorDOMAgent::removeNode(ErrorString* errorString, int nodeId) 729 { 730 Node* node = assertEditableNode(errorString, nodeId); 731 if (!node) 732 return; 733 734 ContainerNode* parentNode = node->parentNode(); 735 if (!parentNode) { 736 *errorString = "Can not remove detached node"; 737 return; 738 } 739 740 m_domEditor->removeChild(parentNode, node, errorString); 741 } 742 743 void InspectorDOMAgent::setNodeName(ErrorString* errorString, int nodeId, const String& tagName, int* newId) 744 { 745 *newId = 0; 746 747 Node* oldNode = nodeForId(nodeId); 748 if (!oldNode || !oldNode->isElementNode()) 749 return; 750 751 TrackExceptionState es; 752 RefPtr<Element> newElem = oldNode->document()->createElement(tagName, es); 753 if (es.hadException()) 754 return; 755 756 // Copy over the original node's attributes. 757 newElem->cloneAttributesFromElement(*toElement(oldNode)); 758 759 // Copy over the original node's children. 760 Node* child; 761 while ((child = oldNode->firstChild())) { 762 if (!m_domEditor->insertBefore(newElem.get(), child, 0, errorString)) 763 return; 764 } 765 766 // Replace the old node with the new node 767 ContainerNode* parent = oldNode->parentNode(); 768 if (!m_domEditor->insertBefore(parent, newElem.get(), oldNode->nextSibling(), errorString)) 769 return; 770 if (!m_domEditor->removeChild(parent, oldNode, errorString)) 771 return; 772 773 *newId = pushNodePathToFrontend(newElem.get()); 774 if (m_childrenRequested.contains(nodeId)) 775 pushChildNodesToFrontend(*newId); 776 } 777 778 void InspectorDOMAgent::getOuterHTML(ErrorString* errorString, int nodeId, WTF::String* outerHTML) 779 { 780 Node* node = assertNode(errorString, nodeId); 781 if (!node) 782 return; 783 784 *outerHTML = createMarkup(node); 785 } 786 787 void InspectorDOMAgent::setOuterHTML(ErrorString* errorString, int nodeId, const String& outerHTML) 788 { 789 if (!nodeId) { 790 DOMPatchSupport domPatchSupport(m_domEditor.get(), m_document.get()); 791 domPatchSupport.patchDocument(outerHTML); 792 return; 793 } 794 795 Node* node = assertEditableNode(errorString, nodeId); 796 if (!node) 797 return; 798 799 Document* document = node->isDocumentNode() ? toDocument(node) : node->ownerDocument(); 800 if (!document || (!document->isHTMLDocument() && !document->isXHTMLDocument() && !document->isSVGDocument())) { 801 *errorString = "Not an HTML/XML document"; 802 return; 803 } 804 805 Node* newNode = 0; 806 if (!m_domEditor->setOuterHTML(node, outerHTML, &newNode, errorString)) 807 return; 808 809 if (!newNode) { 810 // The only child node has been deleted. 811 return; 812 } 813 814 int newId = pushNodePathToFrontend(newNode); 815 816 bool childrenRequested = m_childrenRequested.contains(nodeId); 817 if (childrenRequested) 818 pushChildNodesToFrontend(newId); 819 } 820 821 void InspectorDOMAgent::setNodeValue(ErrorString* errorString, int nodeId, const String& value) 822 { 823 Node* node = assertEditableNode(errorString, nodeId); 824 if (!node) 825 return; 826 827 if (node->nodeType() != Node::TEXT_NODE) { 828 *errorString = "Can only set value of text nodes"; 829 return; 830 } 831 832 m_domEditor->replaceWholeText(toText(node), value, errorString); 833 } 834 835 void InspectorDOMAgent::getEventListenersForNode(ErrorString* errorString, int nodeId, const String* objectGroup, RefPtr<TypeBuilder::Array<TypeBuilder::DOM::EventListener> >& listenersArray) 836 { 837 listenersArray = TypeBuilder::Array<TypeBuilder::DOM::EventListener>::create(); 838 Node* node = assertNode(errorString, nodeId); 839 if (!node) 840 return; 841 Vector<EventListenerInfo> eventInformation; 842 getEventListeners(node, eventInformation, true); 843 844 // Get Capturing Listeners (in this order) 845 size_t eventInformationLength = eventInformation.size(); 846 for (size_t i = 0; i < eventInformationLength; ++i) { 847 const EventListenerInfo& info = eventInformation[i]; 848 const EventListenerVector& vector = info.eventListenerVector; 849 for (size_t j = 0; j < vector.size(); ++j) { 850 const RegisteredEventListener& listener = vector[j]; 851 if (listener.useCapture) 852 listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup)); 853 } 854 } 855 856 // Get Bubbling Listeners (reverse order) 857 for (size_t i = eventInformationLength; i; --i) { 858 const EventListenerInfo& info = eventInformation[i - 1]; 859 const EventListenerVector& vector = info.eventListenerVector; 860 for (size_t j = 0; j < vector.size(); ++j) { 861 const RegisteredEventListener& listener = vector[j]; 862 if (!listener.useCapture) 863 listenersArray->addItem(buildObjectForEventListener(listener, info.eventType, info.node, objectGroup)); 864 } 865 } 866 } 867 868 void InspectorDOMAgent::getEventListeners(Node* node, Vector<EventListenerInfo>& eventInformation, bool includeAncestors) 869 { 870 // The Node's Ancestors including self. 871 Vector<Node*> ancestors; 872 // Push this node as the firs element. 873 ancestors.append(node); 874 if (includeAncestors) { 875 for (ContainerNode* ancestor = node->parentOrShadowHostNode(); ancestor; ancestor = ancestor->parentOrShadowHostNode()) 876 ancestors.append(ancestor); 877 } 878 879 // Nodes and their Listeners for the concerned event types (order is top to bottom) 880 for (size_t i = ancestors.size(); i; --i) { 881 Node* ancestor = ancestors[i - 1]; 882 EventTargetData* d = ancestor->eventTargetData(); 883 if (!d) 884 continue; 885 // Get the list of event types this Node is concerned with 886 Vector<AtomicString> eventTypes = d->eventListenerMap.eventTypes(); 887 for (size_t j = 0; j < eventTypes.size(); ++j) { 888 AtomicString& type = eventTypes[j]; 889 const EventListenerVector& listeners = ancestor->getEventListeners(type); 890 EventListenerVector filteredListeners; 891 filteredListeners.reserveCapacity(listeners.size()); 892 for (size_t k = 0; k < listeners.size(); ++k) { 893 if (listeners[k].listener->type() == EventListener::JSEventListenerType) 894 filteredListeners.append(listeners[k]); 895 } 896 if (!filteredListeners.isEmpty()) 897 eventInformation.append(EventListenerInfo(ancestor, type, filteredListeners)); 898 } 899 } 900 } 901 902 void InspectorDOMAgent::performSearch(ErrorString*, const String& whitespaceTrimmedQuery, String* searchId, int* resultCount) 903 { 904 // FIXME: Few things are missing here: 905 // 1) Search works with node granularity - number of matches within node is not calculated. 906 // 2) There is no need to push all search results to the front-end at a time, pushing next / previous result 907 // is sufficient. 908 909 unsigned queryLength = whitespaceTrimmedQuery.length(); 910 bool startTagFound = !whitespaceTrimmedQuery.find('<'); 911 bool endTagFound = whitespaceTrimmedQuery.reverseFind('>') + 1 == queryLength; 912 bool startQuoteFound = !whitespaceTrimmedQuery.find('"'); 913 bool endQuoteFound = whitespaceTrimmedQuery.reverseFind('"') + 1 == queryLength; 914 bool exactAttributeMatch = startQuoteFound && endQuoteFound; 915 916 String tagNameQuery = whitespaceTrimmedQuery; 917 String attributeQuery = whitespaceTrimmedQuery; 918 if (startTagFound) 919 tagNameQuery = tagNameQuery.right(tagNameQuery.length() - 1); 920 if (endTagFound) 921 tagNameQuery = tagNameQuery.left(tagNameQuery.length() - 1); 922 if (startQuoteFound) 923 attributeQuery = attributeQuery.right(attributeQuery.length() - 1); 924 if (endQuoteFound) 925 attributeQuery = attributeQuery.left(attributeQuery.length() - 1); 926 927 Vector<Document*> docs = documents(); 928 ListHashSet<Node*> resultCollector; 929 930 for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) { 931 Document* document = *it; 932 Node* node = document->documentElement(); 933 if (!node) 934 continue; 935 936 // Manual plain text search. 937 while ((node = NodeTraversal::next(node, document->documentElement()))) { 938 switch (node->nodeType()) { 939 case Node::TEXT_NODE: 940 case Node::COMMENT_NODE: 941 case Node::CDATA_SECTION_NODE: { 942 String text = node->nodeValue(); 943 if (text.findIgnoringCase(whitespaceTrimmedQuery) != notFound) 944 resultCollector.add(node); 945 break; 946 } 947 case Node::ELEMENT_NODE: { 948 if ((!startTagFound && !endTagFound && (node->nodeName().findIgnoringCase(tagNameQuery) != notFound)) 949 || (startTagFound && endTagFound && equalIgnoringCase(node->nodeName(), tagNameQuery)) 950 || (startTagFound && !endTagFound && node->nodeName().startsWith(tagNameQuery, false)) 951 || (!startTagFound && endTagFound && node->nodeName().endsWith(tagNameQuery, false))) { 952 resultCollector.add(node); 953 break; 954 } 955 // Go through all attributes and serialize them. 956 const Element* element = toElement(node); 957 if (!element->hasAttributes()) 958 break; 959 960 unsigned numAttrs = element->attributeCount(); 961 for (unsigned i = 0; i < numAttrs; ++i) { 962 // Add attribute pair 963 const Attribute* attribute = element->attributeItem(i); 964 if (attribute->localName().find(whitespaceTrimmedQuery) != notFound) { 965 resultCollector.add(node); 966 break; 967 } 968 size_t foundPosition = attribute->value().find(attributeQuery); 969 if (foundPosition != notFound) { 970 if (!exactAttributeMatch || (!foundPosition && attribute->value().length() == attributeQuery.length())) { 971 resultCollector.add(node); 972 break; 973 } 974 } 975 } 976 break; 977 } 978 default: 979 break; 980 } 981 } 982 983 // XPath evaluation 984 for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) { 985 Document* document = *it; 986 TrackExceptionState es; 987 RefPtr<XPathResult> result = DocumentXPathEvaluator::evaluate(document, whitespaceTrimmedQuery, document, 0, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE, 0, es); 988 if (es.hadException() || !result) 989 continue; 990 991 unsigned long size = result->snapshotLength(es); 992 for (unsigned long i = 0; !es.hadException() && i < size; ++i) { 993 Node* node = result->snapshotItem(i, es); 994 if (es.hadException()) 995 break; 996 997 if (node->nodeType() == Node::ATTRIBUTE_NODE) 998 node = toAttr(node)->ownerElement(); 999 resultCollector.add(node); 1000 } 1001 } 1002 1003 // Selector evaluation 1004 for (Vector<Document*>::iterator it = docs.begin(); it != docs.end(); ++it) { 1005 Document* document = *it; 1006 TrackExceptionState es; 1007 RefPtr<NodeList> nodeList = document->querySelectorAll(whitespaceTrimmedQuery, es); 1008 if (es.hadException() || !nodeList) 1009 continue; 1010 1011 unsigned size = nodeList->length(); 1012 for (unsigned i = 0; i < size; ++i) 1013 resultCollector.add(nodeList->item(i)); 1014 } 1015 } 1016 1017 *searchId = IdentifiersFactory::createIdentifier(); 1018 SearchResults::iterator resultsIt = m_searchResults.add(*searchId, Vector<RefPtr<Node> >()).iterator; 1019 1020 for (ListHashSet<Node*>::iterator it = resultCollector.begin(); it != resultCollector.end(); ++it) 1021 resultsIt->value.append(*it); 1022 1023 *resultCount = resultsIt->value.size(); 1024 } 1025 1026 void InspectorDOMAgent::getSearchResults(ErrorString* errorString, const String& searchId, int fromIndex, int toIndex, RefPtr<TypeBuilder::Array<int> >& nodeIds) 1027 { 1028 SearchResults::iterator it = m_searchResults.find(searchId); 1029 if (it == m_searchResults.end()) { 1030 *errorString = "No search session with given id found"; 1031 return; 1032 } 1033 1034 int size = it->value.size(); 1035 if (fromIndex < 0 || toIndex > size || fromIndex >= toIndex) { 1036 *errorString = "Invalid search result range"; 1037 return; 1038 } 1039 1040 nodeIds = TypeBuilder::Array<int>::create(); 1041 for (int i = fromIndex; i < toIndex; ++i) 1042 nodeIds->addItem(pushNodePathToFrontend((it->value)[i].get())); 1043 } 1044 1045 void InspectorDOMAgent::discardSearchResults(ErrorString*, const String& searchId) 1046 { 1047 m_searchResults.remove(searchId); 1048 } 1049 1050 bool InspectorDOMAgent::handleMousePress() 1051 { 1052 if (m_searchingForNode == NotSearching) 1053 return false; 1054 1055 if (Node* node = m_overlay->highlightedNode()) { 1056 inspect(node); 1057 return true; 1058 } 1059 return false; 1060 } 1061 1062 bool InspectorDOMAgent::handleGestureEvent(Frame* frame, const PlatformGestureEvent& event) 1063 { 1064 if (m_searchingForNode == NotSearching || event.type() != PlatformEvent::GestureTap) 1065 return false; 1066 Node* node = hoveredNodeForEvent(frame, event, false); 1067 if (node && m_inspectModeHighlightConfig) { 1068 m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig); 1069 inspect(node); 1070 return true; 1071 } 1072 return false; 1073 } 1074 1075 bool InspectorDOMAgent::handleTouchEvent(Frame* frame, const PlatformTouchEvent& event) 1076 { 1077 if (m_searchingForNode == NotSearching) 1078 return false; 1079 Node* node = hoveredNodeForEvent(frame, event, false); 1080 if (node && m_inspectModeHighlightConfig) { 1081 m_overlay->highlightNode(node, 0 /* eventTarget */, *m_inspectModeHighlightConfig); 1082 inspect(node); 1083 return true; 1084 } 1085 return false; 1086 } 1087 1088 void InspectorDOMAgent::inspect(Node* inspectedNode) 1089 { 1090 if (!m_frontend || !inspectedNode) 1091 return; 1092 1093 Node* node = inspectedNode; 1094 if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE) 1095 node = node->parentNode(); 1096 1097 int nodeId = pushNodePathToFrontend(node); 1098 if (nodeId) 1099 m_frontend->inspectNodeRequested(nodeId); 1100 } 1101 1102 void InspectorDOMAgent::handleMouseMove(Frame* frame, const PlatformMouseEvent& event) 1103 { 1104 if (m_searchingForNode == NotSearching) 1105 return; 1106 1107 if (!frame->view() || !frame->contentRenderer()) 1108 return; 1109 Node* node = hoveredNodeForEvent(frame, event, event.shiftKey()); 1110 1111 while (m_searchingForNode != SearchingForShadow && node && node->isInShadowTree()) 1112 node = node->parentOrShadowHostNode(); 1113 1114 Node* eventTarget = event.shiftKey() ? hoveredNodeForEvent(frame, event, false) : 0; 1115 if (eventTarget == node) 1116 eventTarget = 0; 1117 1118 if (node && m_inspectModeHighlightConfig) 1119 m_overlay->highlightNode(node, eventTarget, *m_inspectModeHighlightConfig); 1120 } 1121 1122 void InspectorDOMAgent::setSearchingForNode(ErrorString* errorString, SearchMode searchMode, JSONObject* highlightInspectorObject) 1123 { 1124 if (m_searchingForNode == searchMode) 1125 return; 1126 m_searchingForNode = searchMode; 1127 m_overlay->setInspectModeEnabled(searchMode != NotSearching); 1128 if (searchMode != NotSearching) { 1129 m_inspectModeHighlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject); 1130 if (!m_inspectModeHighlightConfig) 1131 return; 1132 } else 1133 hideHighlight(errorString); 1134 } 1135 1136 PassOwnPtr<HighlightConfig> InspectorDOMAgent::highlightConfigFromInspectorObject(ErrorString* errorString, JSONObject* highlightInspectorObject) 1137 { 1138 if (!highlightInspectorObject) { 1139 *errorString = "Internal error: highlight configuration parameter is missing"; 1140 return nullptr; 1141 } 1142 1143 OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig()); 1144 bool showInfo = false; // Default: false (do not show a tooltip). 1145 highlightInspectorObject->getBoolean("showInfo", &showInfo); 1146 highlightConfig->showInfo = showInfo; 1147 bool showRulers = false; // Default: false (do not show rulers). 1148 highlightInspectorObject->getBoolean("showRulers", &showRulers); 1149 highlightConfig->showRulers = showRulers; 1150 highlightConfig->content = parseConfigColor("contentColor", highlightInspectorObject); 1151 highlightConfig->contentOutline = parseConfigColor("contentOutlineColor", highlightInspectorObject); 1152 highlightConfig->padding = parseConfigColor("paddingColor", highlightInspectorObject); 1153 highlightConfig->border = parseConfigColor("borderColor", highlightInspectorObject); 1154 highlightConfig->margin = parseConfigColor("marginColor", highlightInspectorObject); 1155 highlightConfig->eventTarget = parseConfigColor("eventTargetColor", highlightInspectorObject); 1156 return highlightConfig.release(); 1157 } 1158 1159 void InspectorDOMAgent::setInspectModeEnabled(ErrorString* errorString, bool enabled, const bool* inspectShadowDOM, const RefPtr<JSONObject>* highlightConfig) 1160 { 1161 SearchMode searchMode = enabled ? (inspectShadowDOM && *inspectShadowDOM ? SearchingForShadow : SearchingForNormal) : NotSearching; 1162 setSearchingForNode(errorString, searchMode, highlightConfig ? highlightConfig->get() : 0); 1163 } 1164 1165 void InspectorDOMAgent::highlightRect(ErrorString*, int x, int y, int width, int height, const RefPtr<JSONObject>* color, const RefPtr<JSONObject>* outlineColor) 1166 { 1167 OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad(FloatRect(x, y, width, height))); 1168 innerHighlightQuad(quad.release(), color, outlineColor); 1169 } 1170 1171 void InspectorDOMAgent::highlightQuad(ErrorString* errorString, const RefPtr<JSONArray>& quadArray, const RefPtr<JSONObject>* color, const RefPtr<JSONObject>* outlineColor) 1172 { 1173 OwnPtr<FloatQuad> quad = adoptPtr(new FloatQuad()); 1174 if (!parseQuad(quadArray, quad.get())) { 1175 *errorString = "Invalid Quad format"; 1176 return; 1177 } 1178 innerHighlightQuad(quad.release(), color, outlineColor); 1179 } 1180 1181 void InspectorDOMAgent::innerHighlightQuad(PassOwnPtr<FloatQuad> quad, const RefPtr<JSONObject>* color, const RefPtr<JSONObject>* outlineColor) 1182 { 1183 OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig()); 1184 highlightConfig->content = parseColor(color); 1185 highlightConfig->contentOutline = parseColor(outlineColor); 1186 m_overlay->highlightQuad(quad, *highlightConfig); 1187 } 1188 1189 void InspectorDOMAgent::highlightNode(ErrorString* errorString, const RefPtr<JSONObject>& highlightInspectorObject, const int* nodeId, const String* objectId) 1190 { 1191 Node* node = 0; 1192 if (nodeId) { 1193 node = assertNode(errorString, *nodeId); 1194 } else if (objectId) { 1195 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*objectId); 1196 node = injectedScript.nodeForObjectId(*objectId); 1197 if (!node) 1198 *errorString = "Node for given objectId not found"; 1199 } else 1200 *errorString = "Either nodeId or objectId must be specified"; 1201 1202 if (!node) 1203 return; 1204 1205 OwnPtr<HighlightConfig> highlightConfig = highlightConfigFromInspectorObject(errorString, highlightInspectorObject.get()); 1206 if (!highlightConfig) 1207 return; 1208 1209 m_overlay->highlightNode(node, 0 /* eventTarget */, *highlightConfig); 1210 } 1211 1212 void InspectorDOMAgent::highlightFrame( 1213 ErrorString*, 1214 const String& frameId, 1215 const RefPtr<JSONObject>* color, 1216 const RefPtr<JSONObject>* outlineColor) 1217 { 1218 Frame* frame = m_pageAgent->frameForId(frameId); 1219 if (frame && frame->ownerElement()) { 1220 OwnPtr<HighlightConfig> highlightConfig = adoptPtr(new HighlightConfig()); 1221 highlightConfig->showInfo = true; // Always show tooltips for frames. 1222 highlightConfig->content = parseColor(color); 1223 highlightConfig->contentOutline = parseColor(outlineColor); 1224 m_overlay->highlightNode(frame->ownerElement(), 0 /* eventTarget */, *highlightConfig); 1225 } 1226 } 1227 1228 void InspectorDOMAgent::hideHighlight(ErrorString*) 1229 { 1230 m_overlay->hideHighlight(); 1231 } 1232 1233 void InspectorDOMAgent::moveTo(ErrorString* errorString, int nodeId, int targetElementId, const int* const anchorNodeId, int* newNodeId) 1234 { 1235 Node* node = assertEditableNode(errorString, nodeId); 1236 if (!node) 1237 return; 1238 1239 Element* targetElement = assertEditableElement(errorString, targetElementId); 1240 if (!targetElement) 1241 return; 1242 1243 Node* anchorNode = 0; 1244 if (anchorNodeId && *anchorNodeId) { 1245 anchorNode = assertEditableNode(errorString, *anchorNodeId); 1246 if (!anchorNode) 1247 return; 1248 if (anchorNode->parentNode() != targetElement) { 1249 *errorString = "Anchor node must be child of the target element"; 1250 return; 1251 } 1252 } 1253 1254 if (!m_domEditor->insertBefore(targetElement, node, anchorNode, errorString)) 1255 return; 1256 1257 *newNodeId = pushNodePathToFrontend(node); 1258 } 1259 1260 void InspectorDOMAgent::undo(ErrorString* errorString) 1261 { 1262 TrackExceptionState es; 1263 m_history->undo(es); 1264 *errorString = InspectorDOMAgent::toErrorString(es); 1265 } 1266 1267 void InspectorDOMAgent::redo(ErrorString* errorString) 1268 { 1269 TrackExceptionState es; 1270 m_history->redo(es); 1271 *errorString = InspectorDOMAgent::toErrorString(es); 1272 } 1273 1274 void InspectorDOMAgent::markUndoableState(ErrorString*) 1275 { 1276 m_history->markUndoableState(); 1277 } 1278 1279 void InspectorDOMAgent::focus(ErrorString* errorString, int nodeId) 1280 { 1281 Element* element = assertElement(errorString, nodeId); 1282 if (!element) 1283 return; 1284 if (!element->isFocusable()) { 1285 *errorString = "Element is not focusable"; 1286 return; 1287 } 1288 element->focus(); 1289 } 1290 1291 void InspectorDOMAgent::setFileInputFiles(ErrorString* errorString, int nodeId, const RefPtr<JSONArray>& files) 1292 { 1293 Node* node = assertNode(errorString, nodeId); 1294 if (!node) 1295 return; 1296 if (!node->hasTagName(inputTag) || !toHTMLInputElement(node)->isFileUpload()) { 1297 *errorString = "Node is not a file input element"; 1298 return; 1299 } 1300 1301 RefPtr<FileList> fileList = FileList::create(); 1302 for (JSONArray::const_iterator iter = files->begin(); iter != files->end(); ++iter) { 1303 String path; 1304 if (!(*iter)->asString(&path)) { 1305 *errorString = "Files must be strings"; 1306 return; 1307 } 1308 fileList->append(File::create(path)); 1309 } 1310 toHTMLInputElement(node)->setFiles(fileList); 1311 } 1312 1313 void InspectorDOMAgent::resolveNode(ErrorString* errorString, int nodeId, const String* const objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result) 1314 { 1315 String objectGroupName = objectGroup ? *objectGroup : ""; 1316 Node* node = nodeForId(nodeId); 1317 if (!node) { 1318 *errorString = "No node with given id found"; 1319 return; 1320 } 1321 RefPtr<TypeBuilder::Runtime::RemoteObject> object = resolveNode(node, objectGroupName); 1322 if (!object) { 1323 *errorString = "Node with given id does not belong to the document"; 1324 return; 1325 } 1326 result = object; 1327 } 1328 1329 void InspectorDOMAgent::getAttributes(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<String> >& result) 1330 { 1331 Element* element = assertElement(errorString, nodeId); 1332 if (!element) 1333 return; 1334 1335 result = buildArrayForElementAttributes(element); 1336 } 1337 1338 void InspectorDOMAgent::requestNode(ErrorString*, const String& objectId, int* nodeId) 1339 { 1340 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId); 1341 Node* node = injectedScript.nodeForObjectId(objectId); 1342 if (node) 1343 *nodeId = pushNodePathToFrontend(node); 1344 else 1345 *nodeId = 0; 1346 } 1347 1348 // static 1349 String InspectorDOMAgent::documentURLString(Document* document) 1350 { 1351 if (!document || document->url().isNull()) 1352 return ""; 1353 return document->url().string(); 1354 } 1355 1356 static String documentBaseURLString(Document* document) 1357 { 1358 return document->completeURL("").string(); 1359 } 1360 1361 PassRefPtr<TypeBuilder::DOM::Node> InspectorDOMAgent::buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap) 1362 { 1363 int id = bind(node, nodesMap); 1364 String nodeName; 1365 String localName; 1366 String nodeValue; 1367 1368 switch (node->nodeType()) { 1369 case Node::TEXT_NODE: 1370 case Node::COMMENT_NODE: 1371 case Node::CDATA_SECTION_NODE: 1372 nodeValue = node->nodeValue(); 1373 if (nodeValue.length() > maxTextSize) { 1374 nodeValue = nodeValue.left(maxTextSize); 1375 nodeValue.append(ellipsisUChar); 1376 } 1377 break; 1378 case Node::ATTRIBUTE_NODE: 1379 localName = node->localName(); 1380 break; 1381 case Node::DOCUMENT_FRAGMENT_NODE: 1382 case Node::DOCUMENT_NODE: 1383 case Node::ELEMENT_NODE: 1384 default: 1385 nodeName = node->nodeName(); 1386 localName = node->localName(); 1387 break; 1388 } 1389 1390 RefPtr<TypeBuilder::DOM::Node> value = TypeBuilder::DOM::Node::create() 1391 .setNodeId(id) 1392 .setNodeType(static_cast<int>(node->nodeType())) 1393 .setNodeName(nodeName) 1394 .setLocalName(localName) 1395 .setNodeValue(nodeValue); 1396 1397 bool forcePushChildren = false; 1398 if (node->isElementNode()) { 1399 Element* element = toElement(node); 1400 value->setAttributes(buildArrayForElementAttributes(element)); 1401 if (node->isFrameOwnerElement()) { 1402 HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(node); 1403 Frame* frame = frameOwner->contentFrame(); 1404 if (frame) 1405 value->setFrameId(m_pageAgent->frameId(frame)); 1406 Document* doc = frameOwner->contentDocument(); 1407 if (doc) 1408 value->setContentDocument(buildObjectForNode(doc, 0, nodesMap)); 1409 } 1410 1411 ElementShadow* shadow = element->shadow(); 1412 if (shadow) { 1413 RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > shadowRoots = TypeBuilder::Array<TypeBuilder::DOM::Node>::create(); 1414 for (ShadowRoot* root = shadow->youngestShadowRoot(); root; root = root->olderShadowRoot()) 1415 shadowRoots->addItem(buildObjectForNode(root, 0, nodesMap)); 1416 value->setShadowRoots(shadowRoots); 1417 forcePushChildren = true; 1418 } 1419 1420 if (element->hasTagName(templateTag)) { 1421 value->setTemplateContent(buildObjectForNode(static_cast<HTMLTemplateElement*>(element)->content(), 0, nodesMap)); 1422 forcePushChildren = true; 1423 } 1424 } else if (node->isDocumentNode()) { 1425 Document* document = toDocument(node); 1426 value->setDocumentURL(documentURLString(document)); 1427 value->setBaseURL(documentBaseURLString(document)); 1428 value->setXmlVersion(document->xmlVersion()); 1429 } else if (node->nodeType() == Node::DOCUMENT_TYPE_NODE) { 1430 DocumentType* docType = static_cast<DocumentType*>(node); 1431 value->setPublicId(docType->publicId()); 1432 value->setSystemId(docType->systemId()); 1433 value->setInternalSubset(docType->internalSubset()); 1434 } else if (node->isAttributeNode()) { 1435 Attr* attribute = toAttr(node); 1436 value->setName(attribute->name()); 1437 value->setValue(attribute->value()); 1438 } 1439 1440 if (node->isContainerNode()) { 1441 int nodeCount = innerChildNodeCount(node); 1442 value->setChildNodeCount(nodeCount); 1443 if (forcePushChildren && !depth) 1444 depth = 1; 1445 RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = buildArrayForContainerChildren(node, depth, nodesMap); 1446 if (children->length() > 0 || depth) // Push children along with shadow in any case. 1447 value->setChildren(children.release()); 1448 } 1449 1450 return value.release(); 1451 } 1452 1453 PassRefPtr<TypeBuilder::Array<String> > InspectorDOMAgent::buildArrayForElementAttributes(Element* element) 1454 { 1455 RefPtr<TypeBuilder::Array<String> > attributesValue = TypeBuilder::Array<String>::create(); 1456 // Go through all attributes and serialize them. 1457 if (!element->hasAttributes()) 1458 return attributesValue.release(); 1459 unsigned numAttrs = element->attributeCount(); 1460 for (unsigned i = 0; i < numAttrs; ++i) { 1461 // Add attribute pair 1462 const Attribute* attribute = element->attributeItem(i); 1463 attributesValue->addItem(attribute->name().toString()); 1464 attributesValue->addItem(attribute->value()); 1465 } 1466 return attributesValue.release(); 1467 } 1468 1469 PassRefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > InspectorDOMAgent::buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap) 1470 { 1471 RefPtr<TypeBuilder::Array<TypeBuilder::DOM::Node> > children = TypeBuilder::Array<TypeBuilder::DOM::Node>::create(); 1472 if (depth == 0) { 1473 // Special-case the only text child - pretend that container's children have been requested. 1474 Node* firstChild = container->firstChild(); 1475 if (firstChild && firstChild->nodeType() == Node::TEXT_NODE && !firstChild->nextSibling()) { 1476 children->addItem(buildObjectForNode(firstChild, 0, nodesMap)); 1477 m_childrenRequested.add(bind(container, nodesMap)); 1478 } 1479 return children.release(); 1480 } 1481 1482 Node* child = innerFirstChild(container); 1483 depth--; 1484 m_childrenRequested.add(bind(container, nodesMap)); 1485 1486 while (child) { 1487 children->addItem(buildObjectForNode(child, depth, nodesMap)); 1488 child = innerNextSibling(child); 1489 } 1490 return children.release(); 1491 } 1492 1493 PassRefPtr<TypeBuilder::DOM::EventListener> InspectorDOMAgent::buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node, const String* objectGroupId) 1494 { 1495 RefPtr<EventListener> eventListener = registeredEventListener.listener; 1496 Document* document = node->document(); 1497 RefPtr<TypeBuilder::DOM::EventListener> value = TypeBuilder::DOM::EventListener::create() 1498 .setType(eventType) 1499 .setUseCapture(registeredEventListener.useCapture) 1500 .setIsAttribute(eventListener->isAttribute()) 1501 .setNodeId(pushNodePathToFrontend(node)) 1502 .setHandlerBody(eventListenerHandlerBody(document, eventListener.get())); 1503 if (objectGroupId) { 1504 ScriptValue functionValue = eventListenerHandler(document, eventListener.get()); 1505 if (!functionValue.hasNoValue()) { 1506 Frame* frame = document->frame(); 1507 if (frame) { 1508 ScriptState* scriptState = eventListenerHandlerScriptState(frame, eventListener.get()); 1509 if (scriptState) { 1510 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState); 1511 if (!injectedScript.hasNoValue()) { 1512 RefPtr<TypeBuilder::Runtime::RemoteObject> valueJson = injectedScript.wrapObject(functionValue, *objectGroupId); 1513 value->setHandler(valueJson); 1514 } 1515 } 1516 } 1517 } 1518 } 1519 String sourceName; 1520 String scriptId; 1521 int lineNumber; 1522 if (eventListenerHandlerLocation(node->document(), eventListener.get(), sourceName, scriptId, lineNumber)) { 1523 RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create() 1524 .setScriptId(scriptId) 1525 .setLineNumber(lineNumber); 1526 value->setLocation(location); 1527 if (!sourceName.isEmpty()) 1528 value->setSourceName(sourceName); 1529 } 1530 return value.release(); 1531 } 1532 1533 Node* InspectorDOMAgent::innerFirstChild(Node* node) 1534 { 1535 node = node->firstChild(); 1536 while (isWhitespace(node)) 1537 node = node->nextSibling(); 1538 return node; 1539 } 1540 1541 Node* InspectorDOMAgent::innerNextSibling(Node* node) 1542 { 1543 do { 1544 node = node->nextSibling(); 1545 } while (isWhitespace(node)); 1546 return node; 1547 } 1548 1549 Node* InspectorDOMAgent::innerPreviousSibling(Node* node) 1550 { 1551 do { 1552 node = node->previousSibling(); 1553 } while (isWhitespace(node)); 1554 return node; 1555 } 1556 1557 unsigned InspectorDOMAgent::innerChildNodeCount(Node* node) 1558 { 1559 unsigned count = 0; 1560 Node* child = innerFirstChild(node); 1561 while (child) { 1562 count++; 1563 child = innerNextSibling(child); 1564 } 1565 return count; 1566 } 1567 1568 Node* InspectorDOMAgent::innerParentNode(Node* node) 1569 { 1570 if (node->isDocumentNode()) { 1571 Document* document = toDocument(node); 1572 return document->ownerElement(); 1573 } 1574 return node->parentOrShadowHostNode(); 1575 } 1576 1577 bool InspectorDOMAgent::isWhitespace(Node* node) 1578 { 1579 //TODO: pull ignoreWhitespace setting from the frontend and use here. 1580 return node && node->nodeType() == Node::TEXT_NODE && node->nodeValue().stripWhiteSpace().length() == 0; 1581 } 1582 1583 void InspectorDOMAgent::domContentLoadedEventFired(Frame* frame) 1584 { 1585 if (frame->page()->mainFrame() != frame) 1586 return; 1587 1588 // Re-push document once it is loaded. 1589 discardFrontendBindings(); 1590 if (m_state->getBoolean(DOMAgentState::documentRequested)) 1591 m_frontend->documentUpdated(); 1592 } 1593 1594 void InspectorDOMAgent::loadEventFired(Frame* frame) 1595 { 1596 Element* frameOwner = frame->document()->ownerElement(); 1597 if (!frameOwner) 1598 return; 1599 1600 int frameOwnerId = m_documentNodeToIdMap.get(frameOwner); 1601 if (!frameOwnerId) 1602 return; 1603 1604 // Re-add frame owner element together with its new children. 1605 int parentId = m_documentNodeToIdMap.get(innerParentNode(frameOwner)); 1606 m_frontend->childNodeRemoved(parentId, frameOwnerId); 1607 unbind(frameOwner, &m_documentNodeToIdMap); 1608 1609 RefPtr<TypeBuilder::DOM::Node> value = buildObjectForNode(frameOwner, 0, &m_documentNodeToIdMap); 1610 Node* previousSibling = innerPreviousSibling(frameOwner); 1611 int prevId = previousSibling ? m_documentNodeToIdMap.get(previousSibling) : 0; 1612 m_frontend->childNodeInserted(parentId, prevId, value.release()); 1613 } 1614 1615 void InspectorDOMAgent::didCommitLoad(Frame* frame, DocumentLoader* loader) 1616 { 1617 Frame* mainFrame = frame->page()->mainFrame(); 1618 if (loader->frame() != mainFrame) 1619 return; 1620 1621 setDocument(mainFrame->document()); 1622 } 1623 1624 void InspectorDOMAgent::didInsertDOMNode(Node* node) 1625 { 1626 if (isWhitespace(node)) 1627 return; 1628 1629 // We could be attaching existing subtree. Forget the bindings. 1630 unbind(node, &m_documentNodeToIdMap); 1631 1632 ContainerNode* parent = node->parentNode(); 1633 if (!parent) 1634 return; 1635 1636 int parentId = m_documentNodeToIdMap.get(parent); 1637 // Return if parent is not mapped yet. 1638 if (!parentId) 1639 return; 1640 1641 if (!m_childrenRequested.contains(parentId)) { 1642 // No children are mapped yet -> only notify on changes of hasChildren. 1643 m_frontend->childNodeCountUpdated(parentId, innerChildNodeCount(parent)); 1644 } else { 1645 // Children have been requested -> return value of a new child. 1646 Node* prevSibling = innerPreviousSibling(node); 1647 int prevId = prevSibling ? m_documentNodeToIdMap.get(prevSibling) : 0; 1648 RefPtr<TypeBuilder::DOM::Node> value = buildObjectForNode(node, 0, &m_documentNodeToIdMap); 1649 m_frontend->childNodeInserted(parentId, prevId, value.release()); 1650 } 1651 } 1652 1653 void InspectorDOMAgent::willRemoveDOMNode(Node* node) 1654 { 1655 if (isWhitespace(node)) 1656 return; 1657 1658 ContainerNode* parent = node->parentNode(); 1659 1660 // If parent is not mapped yet -> ignore the event. 1661 if (!m_documentNodeToIdMap.contains(parent)) 1662 return; 1663 1664 int parentId = m_documentNodeToIdMap.get(parent); 1665 1666 if (!m_childrenRequested.contains(parentId)) { 1667 // No children are mapped yet -> only notify on changes of hasChildren. 1668 if (innerChildNodeCount(parent) == 1) 1669 m_frontend->childNodeCountUpdated(parentId, 0); 1670 } else 1671 m_frontend->childNodeRemoved(parentId, m_documentNodeToIdMap.get(node)); 1672 unbind(node, &m_documentNodeToIdMap); 1673 } 1674 1675 void InspectorDOMAgent::willModifyDOMAttr(Element*, const AtomicString& oldValue, const AtomicString& newValue) 1676 { 1677 m_suppressAttributeModifiedEvent = (oldValue == newValue); 1678 } 1679 1680 void InspectorDOMAgent::didModifyDOMAttr(Element* element, const AtomicString& name, const AtomicString& value) 1681 { 1682 bool shouldSuppressEvent = m_suppressAttributeModifiedEvent; 1683 m_suppressAttributeModifiedEvent = false; 1684 if (shouldSuppressEvent) 1685 return; 1686 1687 int id = boundNodeId(element); 1688 // If node is not mapped yet -> ignore the event. 1689 if (!id) 1690 return; 1691 1692 if (m_domListener) 1693 m_domListener->didModifyDOMAttr(element); 1694 1695 m_frontend->attributeModified(id, name, value); 1696 } 1697 1698 void InspectorDOMAgent::didRemoveDOMAttr(Element* element, const AtomicString& name) 1699 { 1700 int id = boundNodeId(element); 1701 // If node is not mapped yet -> ignore the event. 1702 if (!id) 1703 return; 1704 1705 if (m_domListener) 1706 m_domListener->didModifyDOMAttr(element); 1707 1708 m_frontend->attributeRemoved(id, name); 1709 } 1710 1711 void InspectorDOMAgent::styleAttributeInvalidated(const Vector<Element*>& elements) 1712 { 1713 RefPtr<TypeBuilder::Array<int> > nodeIds = TypeBuilder::Array<int>::create(); 1714 for (unsigned i = 0, size = elements.size(); i < size; ++i) { 1715 Element* element = elements.at(i); 1716 int id = boundNodeId(element); 1717 // If node is not mapped yet -> ignore the event. 1718 if (!id) 1719 continue; 1720 1721 if (m_domListener) 1722 m_domListener->didModifyDOMAttr(element); 1723 nodeIds->addItem(id); 1724 } 1725 m_frontend->inlineStyleInvalidated(nodeIds.release()); 1726 } 1727 1728 void InspectorDOMAgent::characterDataModified(CharacterData* characterData) 1729 { 1730 int id = m_documentNodeToIdMap.get(characterData); 1731 if (!id) { 1732 // Push text node if it is being created. 1733 didInsertDOMNode(characterData); 1734 return; 1735 } 1736 m_frontend->characterDataModified(id, characterData->data()); 1737 } 1738 1739 void InspectorDOMAgent::didInvalidateStyleAttr(Node* node) 1740 { 1741 int id = m_documentNodeToIdMap.get(node); 1742 // If node is not mapped yet -> ignore the event. 1743 if (!id) 1744 return; 1745 1746 if (!m_revalidateStyleAttrTask) 1747 m_revalidateStyleAttrTask = adoptPtr(new RevalidateStyleAttributeTask(this)); 1748 m_revalidateStyleAttrTask->scheduleFor(toElement(node)); 1749 } 1750 1751 void InspectorDOMAgent::didPushShadowRoot(Element* host, ShadowRoot* root) 1752 { 1753 if (!host->ownerDocument()) 1754 return; 1755 1756 int hostId = m_documentNodeToIdMap.get(host); 1757 if (hostId) 1758 m_frontend->shadowRootPushed(hostId, buildObjectForNode(root, 0, &m_documentNodeToIdMap)); 1759 } 1760 1761 void InspectorDOMAgent::willPopShadowRoot(Element* host, ShadowRoot* root) 1762 { 1763 if (!host->ownerDocument()) 1764 return; 1765 1766 int hostId = m_documentNodeToIdMap.get(host); 1767 int rootId = m_documentNodeToIdMap.get(root); 1768 if (hostId && rootId) 1769 m_frontend->shadowRootPopped(hostId, rootId); 1770 } 1771 1772 void InspectorDOMAgent::frameDocumentUpdated(Frame* frame) 1773 { 1774 Document* document = frame->document(); 1775 if (!document) 1776 return; 1777 1778 Page* page = frame->page(); 1779 ASSERT(page); 1780 if (frame != page->mainFrame()) 1781 return; 1782 1783 // Only update the main frame document, nested frame document updates are not required 1784 // (will be handled by loadEventFired()). 1785 setDocument(document); 1786 } 1787 1788 Node* InspectorDOMAgent::nodeForPath(const String& path) 1789 { 1790 // The path is of form "1,HTML,2,BODY,1,DIV" 1791 if (!m_document) 1792 return 0; 1793 1794 Node* node = m_document.get(); 1795 Vector<String> pathTokens; 1796 path.split(",", false, pathTokens); 1797 if (!pathTokens.size()) 1798 return 0; 1799 for (size_t i = 0; i < pathTokens.size() - 1; i += 2) { 1800 bool success = true; 1801 unsigned childNumber = pathTokens[i].toUInt(&success); 1802 if (!success) 1803 return 0; 1804 if (childNumber >= innerChildNodeCount(node)) 1805 return 0; 1806 1807 Node* child = innerFirstChild(node); 1808 String childName = pathTokens[i + 1]; 1809 for (size_t j = 0; child && j < childNumber; ++j) 1810 child = innerNextSibling(child); 1811 1812 if (!child || child->nodeName() != childName) 1813 return 0; 1814 node = child; 1815 } 1816 return node; 1817 } 1818 1819 void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString* errorString, const String& path, int* nodeId) 1820 { 1821 if (Node* node = nodeForPath(path)) 1822 *nodeId = pushNodePathToFrontend(node); 1823 else 1824 *errorString = "No node with given path found"; 1825 } 1826 1827 void InspectorDOMAgent::pushNodeByBackendIdToFrontend(ErrorString* errorString, BackendNodeId backendNodeId, int* nodeId) 1828 { 1829 if (!m_backendIdToNode.contains(backendNodeId)) { 1830 *errorString = "No node with given backend id found"; 1831 return; 1832 } 1833 1834 Node* node = m_backendIdToNode.get(backendNodeId).first; 1835 String nodeGroup = m_backendIdToNode.get(backendNodeId).second; 1836 *nodeId = pushNodePathToFrontend(node); 1837 1838 if (nodeGroup == "") { 1839 m_backendIdToNode.remove(backendNodeId); 1840 m_nodeGroupToBackendIdMap.find(nodeGroup)->value.remove(node); 1841 } 1842 } 1843 1844 PassRefPtr<TypeBuilder::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup) 1845 { 1846 Document* document = node->isDocumentNode() ? node->document() : node->ownerDocument(); 1847 Frame* frame = document ? document->frame() : 0; 1848 if (!frame) 1849 return 0; 1850 1851 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(mainWorldScriptState(frame)); 1852 if (injectedScript.hasNoValue()) 1853 return 0; 1854 1855 return injectedScript.wrapNode(node, objectGroup); 1856 } 1857 1858 } // namespace WebCore 1859 1860