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