Changeset 107257 in webkit


Ignore:
Timestamp:
Feb 9, 2012 9:42:09 AM (12 years ago)
Author:
pfeldman@chromium.org
Message:

Web Inspector: rename DOMEditor to DOMPatchSupport, move undoable actions from
InspectorDOMAgent to the new DOMEditor.
https://bugs.webkit.org/show_bug.cgi?id=78245

Reviewed by Yury Semikhatsky.

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • Target.pri:
  • WebCore.gypi:
  • WebCore.vcproj/WebCore.vcproj:
  • WebCore.xcodeproj/project.pbxproj:
  • inspector/DOMEditor.cpp:

(DOMEditor::DOMAction):
(WebCore::DOMEditor::DOMAction::DOMAction):
(WebCore::DOMEditor::DOMAction::perform):
(WebCore::DOMEditor::DOMAction::undo):
(DOMEditor::RemoveChildAction):
(WebCore::DOMEditor::RemoveChildAction::RemoveChildAction):
(WebCore::DOMEditor::RemoveChildAction::perform):
(WebCore::DOMEditor::RemoveChildAction::undo):
(DOMEditor::InsertBeforeAction):
(WebCore::DOMEditor::InsertBeforeAction::InsertBeforeAction):
(WebCore::DOMEditor::InsertBeforeAction::perform):
(WebCore::DOMEditor::InsertBeforeAction::undo):
(DOMEditor::RemoveAttributeAction):
(WebCore::DOMEditor::RemoveAttributeAction::RemoveAttributeAction):
(WebCore::DOMEditor::RemoveAttributeAction::perform):
(WebCore::DOMEditor::RemoveAttributeAction::undo):
(DOMEditor::SetAttributeAction):
(WebCore::DOMEditor::SetAttributeAction::SetAttributeAction):
(WebCore::DOMEditor::SetAttributeAction::perform):
(WebCore::DOMEditor::SetAttributeAction::undo):
(DOMEditor::SetOuterHTMLAction):
(WebCore::DOMEditor::SetOuterHTMLAction::SetOuterHTMLAction):
(WebCore::DOMEditor::SetOuterHTMLAction::perform):
(WebCore::DOMEditor::SetOuterHTMLAction::undo):
(WebCore::DOMEditor::SetOuterHTMLAction::newNode):
(DOMEditor::ReplaceWholeTextAction):
(WebCore::DOMEditor::ReplaceWholeTextAction::ReplaceWholeTextAction):
(WebCore::DOMEditor::ReplaceWholeTextAction::perform):
(WebCore::DOMEditor::ReplaceWholeTextAction::undo):
(WebCore::DOMEditor::DOMEditor):
(WebCore):
(WebCore::DOMEditor::~DOMEditor):
(WebCore::DOMEditor::insertBefore):
(WebCore::DOMEditor::removeChild):
(WebCore::DOMEditor::setAttribute):
(WebCore::DOMEditor::removeAttribute):
(WebCore::DOMEditor::setOuterHTML):
(WebCore::DOMEditor::replaceWholeText):

  • inspector/DOMEditor.h:

(WebCore):
(DOMEditor):

  • inspector/DOMPatchSupport.cpp: Copied from Source/WebCore/inspector/DOMEditor.cpp.

(WebCore::DOMPatchSupport::DOMPatchSupport):
(WebCore::DOMPatchSupport::~DOMPatchSupport):
(WebCore::DOMPatchSupport::patchDocument):
(WebCore::DOMPatchSupport::patchNode):
(WebCore::DOMPatchSupport::innerPatchNode):
(WebCore):
(WebCore::DOMPatchSupport::diff):
(WebCore::DOMPatchSupport::innerPatchChildren):
(WebCore::DOMPatchSupport::createDigest):
(WebCore::DOMPatchSupport::insertBefore):
(WebCore::DOMPatchSupport::removeChild):
(WebCore::DOMPatchSupport::markNodeAsUsed):
(WebCore::DOMPatchSupport::dumpMap):

  • inspector/DOMPatchSupport.h: Copied from Source/WebCore/inspector/DOMEditor.h.

(DOMPatchSupport):

  • inspector/InspectorDOMAgent.cpp:

(WebCore::InspectorDOMAgent::InspectorDOMAgent):
(WebCore::InspectorDOMAgent::setFrontend):
(WebCore::InspectorDOMAgent::clearFrontend):
(WebCore::InspectorDOMAgent::reset):
(WebCore::InspectorDOMAgent::setAttributeValue):
(WebCore::InspectorDOMAgent::setAttributesAsText):
(WebCore::InspectorDOMAgent::removeAttribute):
(WebCore::InspectorDOMAgent::removeNode):
(WebCore::InspectorDOMAgent::setNodeName):
(WebCore::InspectorDOMAgent::setOuterHTML):
(WebCore::InspectorDOMAgent::setNodeValue):
(WebCore::InspectorDOMAgent::moveTo):

  • inspector/InspectorDOMAgent.h:

(WebCore):
(InspectorDOMAgent):

  • inspector/InspectorPageAgent.cpp:

(WebCore::InspectorPageAgent::setDocumentContent):

Location:
trunk/Source/WebCore
Files:
12 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/CMakeLists.txt

    r107194 r107257  
    879879    inspector/DOMEditor.cpp
    880880    inspector/DOMNodeHighlighter.cpp
     881    inspector/DOMPatchSupport.cpp
    881882    inspector/IdentifiersFactory.cpp
    882883    inspector/InjectedScript.cpp
  • trunk/Source/WebCore/ChangeLog

    r107256 r107257  
     12012-02-09  Pavel Feldman  <pfeldman@google.com>
     2
     3        Web Inspector: rename DOMEditor to DOMPatchSupport, move undoable actions from
     4        InspectorDOMAgent to the new DOMEditor.
     5        https://bugs.webkit.org/show_bug.cgi?id=78245
     6
     7        Reviewed by Yury Semikhatsky.
     8
     9        * CMakeLists.txt:
     10        * GNUmakefile.list.am:
     11        * Target.pri:
     12        * WebCore.gypi:
     13        * WebCore.vcproj/WebCore.vcproj:
     14        * WebCore.xcodeproj/project.pbxproj:
     15        * inspector/DOMEditor.cpp:
     16        (DOMEditor::DOMAction):
     17        (WebCore::DOMEditor::DOMAction::DOMAction):
     18        (WebCore::DOMEditor::DOMAction::perform):
     19        (WebCore::DOMEditor::DOMAction::undo):
     20        (DOMEditor::RemoveChildAction):
     21        (WebCore::DOMEditor::RemoveChildAction::RemoveChildAction):
     22        (WebCore::DOMEditor::RemoveChildAction::perform):
     23        (WebCore::DOMEditor::RemoveChildAction::undo):
     24        (DOMEditor::InsertBeforeAction):
     25        (WebCore::DOMEditor::InsertBeforeAction::InsertBeforeAction):
     26        (WebCore::DOMEditor::InsertBeforeAction::perform):
     27        (WebCore::DOMEditor::InsertBeforeAction::undo):
     28        (DOMEditor::RemoveAttributeAction):
     29        (WebCore::DOMEditor::RemoveAttributeAction::RemoveAttributeAction):
     30        (WebCore::DOMEditor::RemoveAttributeAction::perform):
     31        (WebCore::DOMEditor::RemoveAttributeAction::undo):
     32        (DOMEditor::SetAttributeAction):
     33        (WebCore::DOMEditor::SetAttributeAction::SetAttributeAction):
     34        (WebCore::DOMEditor::SetAttributeAction::perform):
     35        (WebCore::DOMEditor::SetAttributeAction::undo):
     36        (DOMEditor::SetOuterHTMLAction):
     37        (WebCore::DOMEditor::SetOuterHTMLAction::SetOuterHTMLAction):
     38        (WebCore::DOMEditor::SetOuterHTMLAction::perform):
     39        (WebCore::DOMEditor::SetOuterHTMLAction::undo):
     40        (WebCore::DOMEditor::SetOuterHTMLAction::newNode):
     41        (DOMEditor::ReplaceWholeTextAction):
     42        (WebCore::DOMEditor::ReplaceWholeTextAction::ReplaceWholeTextAction):
     43        (WebCore::DOMEditor::ReplaceWholeTextAction::perform):
     44        (WebCore::DOMEditor::ReplaceWholeTextAction::undo):
     45        (WebCore::DOMEditor::DOMEditor):
     46        (WebCore):
     47        (WebCore::DOMEditor::~DOMEditor):
     48        (WebCore::DOMEditor::insertBefore):
     49        (WebCore::DOMEditor::removeChild):
     50        (WebCore::DOMEditor::setAttribute):
     51        (WebCore::DOMEditor::removeAttribute):
     52        (WebCore::DOMEditor::setOuterHTML):
     53        (WebCore::DOMEditor::replaceWholeText):
     54        * inspector/DOMEditor.h:
     55        (WebCore):
     56        (DOMEditor):
     57        * inspector/DOMPatchSupport.cpp: Copied from Source/WebCore/inspector/DOMEditor.cpp.
     58        (WebCore::DOMPatchSupport::DOMPatchSupport):
     59        (WebCore::DOMPatchSupport::~DOMPatchSupport):
     60        (WebCore::DOMPatchSupport::patchDocument):
     61        (WebCore::DOMPatchSupport::patchNode):
     62        (WebCore::DOMPatchSupport::innerPatchNode):
     63        (WebCore):
     64        (WebCore::DOMPatchSupport::diff):
     65        (WebCore::DOMPatchSupport::innerPatchChildren):
     66        (WebCore::DOMPatchSupport::createDigest):
     67        (WebCore::DOMPatchSupport::insertBefore):
     68        (WebCore::DOMPatchSupport::removeChild):
     69        (WebCore::DOMPatchSupport::markNodeAsUsed):
     70        (WebCore::DOMPatchSupport::dumpMap):
     71        * inspector/DOMPatchSupport.h: Copied from Source/WebCore/inspector/DOMEditor.h.
     72        (DOMPatchSupport):
     73        * inspector/InspectorDOMAgent.cpp:
     74        (WebCore::InspectorDOMAgent::InspectorDOMAgent):
     75        (WebCore::InspectorDOMAgent::setFrontend):
     76        (WebCore::InspectorDOMAgent::clearFrontend):
     77        (WebCore::InspectorDOMAgent::reset):
     78        (WebCore::InspectorDOMAgent::setAttributeValue):
     79        (WebCore::InspectorDOMAgent::setAttributesAsText):
     80        (WebCore::InspectorDOMAgent::removeAttribute):
     81        (WebCore::InspectorDOMAgent::removeNode):
     82        (WebCore::InspectorDOMAgent::setNodeName):
     83        (WebCore::InspectorDOMAgent::setOuterHTML):
     84        (WebCore::InspectorDOMAgent::setNodeValue):
     85        (WebCore::InspectorDOMAgent::moveTo):
     86        * inspector/InspectorDOMAgent.h:
     87        (WebCore):
     88        (InspectorDOMAgent):
     89        * inspector/InspectorPageAgent.cpp:
     90        (WebCore::InspectorPageAgent::setDocumentContent):
     91
    1922012-02-09  Mark Rowe  <mrowe@apple.com>
    293
  • trunk/Source/WebCore/GNUmakefile.list.am

    r107175 r107257  
    23452345        Source/WebCore/inspector/DOMNodeHighlighter.cpp \
    23462346        Source/WebCore/inspector/DOMNodeHighlighter.h \
     2347        Source/WebCore/inspector/DOMPatchSupport.cpp \
     2348        Source/WebCore/inspector/DOMPatchSupport.h \
    23472349        Source/WebCore/inspector/DOMWrapperVisitor.h \
    23482350        Source/WebCore/inspector/IdentifiersFactory.cpp \
  • trunk/Source/WebCore/Target.pri

    r107175 r107257  
    856856    inspector/DOMEditor.cpp \
    857857    inspector/DOMNodeHighlighter.cpp \
     858    inspector/DOMPatchSupport.cpp \
    858859    inspector/IdentifiersFactory.cpp \
    859860    inspector/InjectedScript.cpp \
     
    19211922    inspector/DOMEditor.h \
    19221923    inspector/DOMNodeHighlighter.h \
     1924    inspector/DOMPatchSupport.h \
    19231925    inspector/DOMWrapperVisitor.h \
    19241926    inspector/IdentifiersFactory.h \
  • trunk/Source/WebCore/WebCore.gypi

    r107235 r107257  
    23442344            'inspector/DOMNodeHighlighter.cpp',
    23452345            'inspector/DOMNodeHighlighter.h',
     2346            'inspector/DOMPatchSupport.cpp',
     2347            'inspector/DOMPatchSupport.h',
    23462348            'inspector/DOMWrapperVisitor.h',
    23472349            'inspector/IdentifiersFactory.cpp',
  • trunk/Source/WebCore/WebCore.vcproj/WebCore.vcproj

    r107235 r107257  
    7115571155                        </File>
    7115671156                        <File
     71157                                RelativePath="..\inspector\DOMPatchSupport.cpp"
     71158                                >
     71159                        </File>
     71160                        <File
     71161                                RelativePath="..\inspector\DOMPatchSupport.h"
     71162                                >
     71163                        </File>
     71164                        <File
    7115771165                                RelativePath="..\inspector\DOMWrapperVisitor.h"
    7115871166                                >
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r107175 r107257  
    18911891                7A54857F14E02D51006AE05A /* InspectorHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A54857D14E02D51006AE05A /* InspectorHistory.cpp */; };
    18921892                7A54858014E02D51006AE05A /* InspectorHistory.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A54857E14E02D51006AE05A /* InspectorHistory.h */; };
     1893                7A54881714E432A1006AE05A /* DOMPatchSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A54881514E432A1006AE05A /* DOMPatchSupport.h */; };
     1894                7A54881814E432A1006AE05A /* DOMPatchSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A54881614E432A1006AE05A /* DOMPatchSupport.cpp */; };
    18931895                7A674BDB0F9EBF4E006CF099 /* PageGroupLoadDeferrer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A674BD90F9EBF4E006CF099 /* PageGroupLoadDeferrer.cpp */; };
    18941896                7A674BDC0F9EBF4E006CF099 /* PageGroupLoadDeferrer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A674BDA0F9EBF4E006CF099 /* PageGroupLoadDeferrer.h */; };
     
    87748776                7A54857D14E02D51006AE05A /* InspectorHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorHistory.cpp; sourceTree = "<group>"; };
    87758777                7A54857E14E02D51006AE05A /* InspectorHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorHistory.h; sourceTree = "<group>"; };
     8778                7A54881514E432A1006AE05A /* DOMPatchSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMPatchSupport.h; sourceTree = "<group>"; };
     8779                7A54881614E432A1006AE05A /* DOMPatchSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMPatchSupport.cpp; sourceTree = "<group>"; };
    87768780                7A563E5412DE32B000F4536D /* InjectedScriptSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedScriptSource.h; sourceTree = "<group>"; };
    87778781                7A563F9512DF5C9100F4536D /* InjectedScriptSource.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = InjectedScriptSource.js; sourceTree = "<group>"; };
     
    1401114015                                4F1442261339FD6200E0D6F8 /* DOMNodeHighlighter.cpp */,
    1401214016                                4F1442271339FD6200E0D6F8 /* DOMNodeHighlighter.h */,
     14017                                7A54881514E432A1006AE05A /* DOMPatchSupport.h */,
     14018                                7A54881614E432A1006AE05A /* DOMPatchSupport.cpp */,
    1401314019                                F35AE5AB14925F5B004D5776 /* DOMWrapperVisitor.h */,
    1401414020                                5913A23F13D49EBA00F5B05C /* IdentifiersFactory.cpp */,
     
    2415624162                                10FB084B14E15C7E00A3DB98 /* PublicURLManager.h in Headers */,
    2415724163                                7A54858014E02D51006AE05A /* InspectorHistory.h in Headers */,
     24164                                7A54881714E432A1006AE05A /* DOMPatchSupport.h in Headers */,
    2415824165                        );
    2415924166                        runOnlyForDeploymentPostprocessing = 0;
     
    2709327100                                7A54857F14E02D51006AE05A /* InspectorHistory.cpp in Sources */,
    2709427101                                CDAA8D0A14D71B2E0061EA60 /* PlatformClockCM.mm in Sources */,
     27102                                7A54881814E432A1006AE05A /* DOMPatchSupport.cpp in Sources */,
    2709527103                        );
    2709627104                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/Source/WebCore/inspector/DOMEditor.cpp

    r107242 r107257  
    3434#if ENABLE(INSPECTOR)
    3535
    36 #include "Attribute.h"
    37 #include "Base64.h"
     36#include "DOMPatchSupport.h"
    3837#include "Document.h"
    39 #include "DocumentFragment.h"
    40 #include "HTMLDocument.h"
    41 #include "HTMLDocumentParser.h"
    42 #include "HTMLElement.h"
    43 #include "HTMLHeadElement.h"
    44 #include "HTMLNames.h"
     38#include "Element.h"
     39#include "ExceptionCode.h"
     40#include "InspectorHistory.h"
    4541#include "Node.h"
    46 
    47 #include <wtf/Deque.h>
     42#include "Text.h"
     43
     44#include "markup.h"
     45
    4846#include <wtf/RefPtr.h>
    49 #include <wtf/SHA1.h>
    50 #include <wtf/text/CString.h>
    5147
    5248using namespace std;
     
    5450namespace WebCore {
    5551
    56 using HTMLNames::bodyTag;
    57 using HTMLNames::headTag;
    58 using HTMLNames::htmlTag;
    59 
    60 struct DOMEditor::Digest {
    61     explicit Digest(Node* node) : m_node(node) { }
    62 
    63     String m_sha1;
    64     String m_attrsSHA1;
    65     Node* m_node;
    66     Vector<OwnPtr<Digest> > m_children;
    67 };
    68 
    69 DOMEditor::DOMEditor(Document* document) : m_document(document) { }
     52class DOMEditor::DOMAction : public InspectorHistory::Action {
     53public:
     54    DOMAction(const String& name) : InspectorHistory::Action(name) { }
     55
     56    virtual bool perform(ErrorString* errorString)
     57    {
     58        ExceptionCode ec = 0;
     59        bool result = perform(ec);
     60        if (ec) {
     61            ExceptionCodeDescription description(ec);
     62            *errorString = description.name;
     63        }
     64        return result && !ec;
     65    }
     66
     67    virtual bool undo(ErrorString* errorString)
     68    {
     69        ExceptionCode ec = 0;
     70        bool result = undo(ec);
     71        if (ec) {
     72            ExceptionCodeDescription description(ec);
     73            *errorString = description.name;
     74        }
     75        return result && !ec;
     76    }
     77
     78    virtual bool perform(ExceptionCode&) = 0;
     79
     80    virtual bool undo(ExceptionCode&) = 0;
     81
     82private:
     83    RefPtr<Node> m_parentNode;
     84    RefPtr<Node> m_node;
     85    RefPtr<Node> m_anchorNode;
     86};
     87
     88class DOMEditor::RemoveChildAction : public DOMEditor::DOMAction {
     89    WTF_MAKE_NONCOPYABLE(RemoveChildAction);
     90public:
     91    RemoveChildAction(Node* parentNode, Node* node)
     92        : DOMEditor::DOMAction("RemoveChild")
     93        , m_parentNode(parentNode)
     94        , m_node(node)
     95    {
     96    }
     97
     98    virtual bool perform(ExceptionCode& ec)
     99    {
     100        m_anchorNode = m_node->nextSibling();
     101        return m_parentNode->removeChild(m_node.get(), ec);
     102    }
     103
     104    virtual bool undo(ExceptionCode& ec)
     105    {
     106        return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);
     107    }
     108
     109private:
     110    RefPtr<Node> m_parentNode;
     111    RefPtr<Node> m_node;
     112    RefPtr<Node> m_anchorNode;
     113};
     114
     115class DOMEditor::InsertBeforeAction : public DOMEditor::DOMAction {
     116    WTF_MAKE_NONCOPYABLE(InsertBeforeAction);
     117public:
     118    InsertBeforeAction(Node* parentNode, Node* node, Node* anchorNode)
     119        : DOMEditor::DOMAction("InsertBefore")
     120        , m_parentNode(parentNode)
     121        , m_node(node)
     122        , m_anchorNode(anchorNode)
     123    {
     124    }
     125
     126    virtual bool perform(ExceptionCode& ec)
     127    {
     128        if (m_node->parentNode()) {
     129            m_removeChildAction = adoptPtr(new RemoveChildAction(m_node->parentNode(), m_node.get()));
     130            if (!m_removeChildAction->perform(ec))
     131                return false;
     132        }
     133        return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);
     134    }
     135
     136    virtual bool undo(ExceptionCode& ec)
     137    {
     138        if (m_removeChildAction)
     139            return m_removeChildAction->undo(ec);
     140
     141        return m_parentNode->removeChild(m_node.get(), ec);
     142    }
     143
     144private:
     145    RefPtr<Node> m_parentNode;
     146    RefPtr<Node> m_node;
     147    RefPtr<Node> m_anchorNode;
     148    OwnPtr<RemoveChildAction> m_removeChildAction;
     149};
     150
     151class DOMEditor::RemoveAttributeAction : public DOMEditor::DOMAction {
     152    WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);
     153public:
     154    RemoveAttributeAction(Element* element, const String& name)
     155        : DOMEditor::DOMAction("RemoveAttribute")
     156        , m_element(element)
     157        , m_name(name)
     158    {
     159    }
     160
     161    virtual bool perform(ExceptionCode&)
     162    {
     163        m_value = m_element->getAttribute(m_name);
     164        m_element->removeAttribute(m_name);
     165        return true;
     166    }
     167
     168    virtual bool undo(ExceptionCode& ec)
     169    {
     170        m_element->setAttribute(m_name, m_value, ec);
     171        return true;
     172    }
     173
     174private:
     175    RefPtr<Element> m_element;
     176    String m_name;
     177    String m_value;
     178};
     179
     180class DOMEditor::SetAttributeAction : public DOMEditor::DOMAction {
     181    WTF_MAKE_NONCOPYABLE(SetAttributeAction);
     182public:
     183    SetAttributeAction(Element* element, const String& name, const String& value)
     184        : DOMEditor::DOMAction("SetAttribute")
     185        , m_element(element)
     186        , m_name(name)
     187        , m_value(value)
     188        , m_hadAttribute(false)
     189    {
     190    }
     191
     192    virtual bool perform(ExceptionCode& ec)
     193    {
     194        m_hadAttribute = m_element->hasAttribute(m_name);
     195        if (m_hadAttribute)
     196            m_oldValue = m_element->getAttribute(m_name);
     197        m_element->setAttribute(m_name, m_value, ec);
     198        return !ec;
     199    }
     200
     201    virtual bool undo(ExceptionCode& ec)
     202    {
     203        if (m_hadAttribute)
     204            m_element->setAttribute(m_name, m_oldValue, ec);
     205        else
     206            m_element->removeAttribute(m_name);
     207        return true;
     208    }
     209
     210private:
     211    RefPtr<Element> m_element;
     212    String m_name;
     213    String m_value;
     214    bool m_hadAttribute;
     215    String m_oldValue;
     216};
     217
     218class DOMEditor::SetOuterHTMLAction : public DOMEditor::DOMAction {
     219    WTF_MAKE_NONCOPYABLE(SetOuterHTMLAction);
     220public:
     221    SetOuterHTMLAction(Node* node, const String& html)
     222        : DOMEditor::DOMAction("SetOuterHTML")
     223        , m_node(node)
     224        , m_nextSibling(node->nextSibling())
     225        , m_html(html)
     226        , m_newNode(0)
     227    {
     228    }
     229
     230    virtual bool perform(ExceptionCode& ec)
     231    {
     232        m_oldHTML = createMarkup(m_node.get());
     233        DOMPatchSupport domPatchSupport(m_node->ownerDocument());
     234        m_newNode = domPatchSupport.patchNode(m_node.get(), m_html, ec);
     235        return !ec;
     236    }
     237
     238    virtual bool undo(ExceptionCode& ec)
     239    {
     240        DOMPatchSupport domPatchSupport(m_newNode->ownerDocument());
     241        Node* node = domPatchSupport.patchNode(m_newNode, m_oldHTML, ec);
     242        if (ec || !node)
     243            return false;
     244        // HTML editing could have produced extra nodes. Remove them if necessary.
     245        node = node->nextSibling();
     246
     247        while (!ec && node && node != m_nextSibling.get()) {
     248            Node* nodeToRemove = node;
     249            node = node->nextSibling();
     250            nodeToRemove->remove(ec);
     251        }
     252        return !ec;
     253    }
     254
     255    Node* newNode()
     256    {
     257        return m_newNode;
     258    }
     259
     260private:
     261    RefPtr<Node> m_node;
     262    RefPtr<Node> m_nextSibling;
     263    String m_html;
     264    String m_oldHTML;
     265    Node* m_newNode;
     266};
     267
     268class DOMEditor::ReplaceWholeTextAction : public DOMEditor::DOMAction {
     269    WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);
     270public:
     271    ReplaceWholeTextAction(Text* textNode, const String& text)
     272        : DOMAction("ReplaceWholeText")
     273        , m_textNode(textNode)
     274        , m_text(text)
     275    {
     276    }
     277
     278    virtual bool perform(ExceptionCode& ec)
     279    {
     280        m_oldText = m_textNode->wholeText();
     281        m_textNode->replaceWholeText(m_text, ec);
     282        return true;
     283    }
     284
     285    virtual bool undo(ExceptionCode& ec)
     286    {
     287        m_textNode->replaceWholeText(m_oldText, ec);
     288        return true;
     289    }
     290
     291private:
     292    RefPtr<Text> m_textNode;
     293    String m_text;
     294    String m_oldText;
     295};
     296
     297DOMEditor::DOMEditor(InspectorHistory* history) : m_history(history) { }
    70298
    71299DOMEditor::~DOMEditor() { }
    72300
    73 void DOMEditor::patchDocument(const String& markup)
    74 {
    75     RefPtr<HTMLDocument> newDocument = HTMLDocument::create(0, KURL());
    76     RefPtr<DocumentParser> parser = HTMLDocumentParser::create(newDocument.get(), false);
    77     parser->insert(markup); // Use insert() so that the parser will not yield.
    78     parser->finish();
    79     parser->detach();
    80 
    81     ExceptionCode ec = 0;
    82     OwnPtr<Digest> oldInfo = createDigest(m_document->documentElement(), 0);
    83     OwnPtr<Digest> newInfo = createDigest(newDocument->documentElement(), &m_unusedNodesMap);
    84     innerPatchNode(oldInfo.get(), newInfo.get(), ec);
    85 
    86     if (ec) {
    87         // Fall back to rewrite.
    88         m_document->write(markup);
    89         m_document->close();
    90     }
    91 }
    92 
    93 Node* DOMEditor::patchNode(Node* node, const String& markup, ExceptionCode& ec)
    94 {
    95     // Don't parse <html> as a fragment.
    96     if (node->isDocumentNode() || (node->parentNode() && node->parentNode()->isDocumentNode())) {
    97         patchDocument(markup);
    98         return 0;
    99     }
    100 
    101     Node* previousSibling = node->previousSibling();
    102     RefPtr<DocumentFragment> fragment = DocumentFragment::create(m_document);
    103     fragment->parseHTML(markup, node->parentElement() ? node->parentElement() : m_document->documentElement());
    104 
    105     // Compose the old list.
    106     ContainerNode* parentNode = node->parentNode();
    107     Vector<OwnPtr<Digest> > oldList;
    108     for (Node* child = parentNode->firstChild(); child; child = child->nextSibling())
    109         oldList.append(createDigest(child, 0));
    110 
    111     // Compose the new list.
    112     String markupCopy = markup;
    113     markupCopy.makeLower();
    114     Vector<OwnPtr<Digest> > newList;
    115     for (Node* child = parentNode->firstChild(); child != node; child = child->nextSibling())
    116         newList.append(createDigest(child, 0));
    117     for (Node* child = fragment->firstChild(); child; child = child->nextSibling()) {
    118         if (child->hasTagName(headTag) && !child->firstChild() && markupCopy.find("</head>") == notFound)
    119             continue; // HTML5 parser inserts empty <head> tag whenever it parses <body>
    120         if (child->hasTagName(bodyTag) && !child->firstChild() && markupCopy.find("</body>") == notFound)
    121             continue; // HTML5 parser inserts empty <body> tag whenever it parses </head>
    122         newList.append(createDigest(child, &m_unusedNodesMap));
    123     }
    124     for (Node* child = node->nextSibling(); child; child = child->nextSibling())
    125         newList.append(createDigest(child, 0));
    126 
    127     innerPatchChildren(parentNode, oldList, newList, ec);
    128     if (ec) {
    129         // Fall back to total replace.
    130         ec = 0;
    131         parentNode->replaceChild(fragment.release(), node, ec);
    132         if (ec)
    133             return 0;
    134     }
    135     return previousSibling ? previousSibling->nextSibling() : parentNode->firstChild();
    136 }
    137 
    138 void DOMEditor::innerPatchNode(Digest* oldDigest, Digest* newDigest, ExceptionCode& ec)
    139 {
    140     if (oldDigest->m_sha1 == newDigest->m_sha1)
    141         return;
    142 
    143     Node* oldNode = oldDigest->m_node;
    144     Node* newNode = newDigest->m_node;
    145 
    146     if (newNode->nodeType() != oldNode->nodeType() || newNode->nodeName() != oldNode->nodeName()) {
    147         oldNode->parentNode()->replaceChild(newNode, oldNode, ec);
    148         return;
    149     }
    150 
    151     if (oldNode->nodeValue() != newNode->nodeValue())
    152         oldNode->setNodeValue(newNode->nodeValue(), ec);
    153     if (ec)
    154         return;
    155 
    156     if (oldNode->nodeType() != Node::ELEMENT_NODE)
    157         return;
    158 
    159     // Patch attributes
    160     Element* oldElement = static_cast<Element*>(oldNode);
    161     Element* newElement = static_cast<Element*>(newNode);
    162     if (oldDigest->m_attrsSHA1 != newDigest->m_attrsSHA1) {
    163         // FIXME: Create a function in Element for removing all properties. Take in account whether did/willModifyAttribute are important.
    164         if (oldElement->hasAttributesWithoutUpdate()) {
    165             while (oldElement->attributeCount())
    166                 oldElement->removeAttribute(0);
    167         }
    168 
    169         // FIXME: Create a function in Element for copying properties. setAttributesFromElement() is close but not enough for this case.
    170         if (newElement->hasAttributesWithoutUpdate()) {
    171             size_t numAttrs = newElement->attributeCount();
    172             for (size_t i = 0; i < numAttrs; ++i) {
    173                 const Attribute* attribute = newElement->attributeItem(i);
    174                 oldElement->setAttribute(attribute->name(), attribute->value());
    175             }
    176         }
    177     }
    178 
    179     innerPatchChildren(oldElement, oldDigest->m_children, newDigest->m_children, ec);
    180     m_unusedNodesMap.remove(newDigest->m_sha1);
    181 }
    182 
    183 pair<DOMEditor::ResultMap, DOMEditor::ResultMap>
    184 DOMEditor::diff(const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList)
    185 {
    186     ResultMap newMap(newList.size());
    187     ResultMap oldMap(oldList.size());
    188 
    189     for (size_t i = 0; i < oldMap.size(); ++i) {
    190         oldMap[i].first = 0;
    191         oldMap[i].second = 0;
    192     }
    193 
    194     for (size_t i = 0; i < newMap.size(); ++i) {
    195         newMap[i].first = 0;
    196         newMap[i].second = 0;
    197     }
    198 
    199     // Trim head and tail.
    200     for (size_t i = 0; i < oldList.size() && i < newList.size() && oldList[i]->m_sha1 == newList[i]->m_sha1; ++i) {
    201         oldMap[i].first = oldList[i].get();
    202         oldMap[i].second = i;
    203         newMap[i].first = newList[i].get();
    204         newMap[i].second = i;
    205     }
    206     for (size_t i = 0; i < oldList.size() && i < newList.size() && oldList[oldList.size() - i - 1]->m_sha1 == newList[newList.size() - i - 1]->m_sha1; ++i) {
    207         size_t oldIndex = oldList.size() - i - 1;
    208         size_t newIndex = newList.size() - i - 1;
    209         oldMap[oldIndex].first = oldList[oldIndex].get();
    210         oldMap[oldIndex].second = newIndex;
    211         newMap[newIndex].first = newList[newIndex].get();
    212         newMap[newIndex].second = oldIndex;
    213     }
    214 
    215     typedef HashMap<String, Vector<size_t> > DiffTable;
    216     DiffTable newTable;
    217     DiffTable oldTable;
    218 
    219     for (size_t i = 0; i < newList.size(); ++i) {
    220         DiffTable::iterator it = newTable.add(newList[i]->m_sha1, Vector<size_t>()).first;
    221         it->second.append(i);
    222     }
    223 
    224     for (size_t i = 0; i < oldList.size(); ++i) {
    225         DiffTable::iterator it = oldTable.add(oldList[i]->m_sha1, Vector<size_t>()).first;
    226         it->second.append(i);
    227     }
    228 
    229     for (DiffTable::iterator newIt = newTable.begin(); newIt != newTable.end(); ++newIt) {
    230         if (newIt->second.size() != 1)
    231             continue;
    232 
    233         DiffTable::iterator oldIt = oldTable.find(newIt->first);
    234         if (oldIt == oldTable.end() || oldIt->second.size() != 1)
    235             continue;
    236 
    237         newMap[newIt->second[0]] = make_pair(newList[newIt->second[0]].get(), oldIt->second[0]);
    238         oldMap[oldIt->second[0]] = make_pair(oldList[oldIt->second[0]].get(), newIt->second[0]);
    239     }
    240 
    241     for (size_t i = 0; newList.size() > 0 && i < newList.size() - 1; ++i) {
    242         if (!newMap[i].first || newMap[i + 1].first)
    243             continue;
    244 
    245         size_t j = newMap[i].second + 1;
    246         if (j < oldMap.size() && !oldMap[j].first && newList[i + 1]->m_sha1 == oldList[j]->m_sha1) {
    247             newMap[i + 1] = make_pair(newList[i + 1].get(), j);
    248             oldMap[j] = make_pair(oldList[j].get(), i + 1);
    249         }
    250     }
    251 
    252     for (size_t i = newList.size() - 1; newList.size() > 0 && i > 0; --i) {
    253         if (!newMap[i].first || newMap[i - 1].first || newMap[i].second <= 0)
    254             continue;
    255 
    256         size_t j = newMap[i].second - 1;
    257         if (!oldMap[j].first && newList[i - 1]->m_sha1 == oldList[j]->m_sha1) {
    258             newMap[i - 1] = make_pair(newList[i - 1].get(), j);
    259             oldMap[j] = make_pair(oldList[j].get(), i - 1);
    260         }
    261     }
    262 
    263 #ifdef DEBUG_DOM_EDITOR
    264     dumpMap(oldMap, "OLD");
    265     dumpMap(newMap, "NEW");
    266 #endif
    267 
    268     return make_pair(oldMap, newMap);
    269 }
    270 
    271 void DOMEditor::innerPatchChildren(ContainerNode* parentNode, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionCode& ec)
    272 {
    273     pair<ResultMap, ResultMap> resultMaps = diff(oldList, newList);
    274     ResultMap& oldMap = resultMaps.first;
    275     ResultMap& newMap = resultMaps.second;
    276 
    277     Digest* oldHead = 0;
    278     Digest* oldBody = 0;
    279 
    280     // 1. First strip everything except for the nodes that retain. Collect pending merges.
    281     HashMap<Digest*, Digest*> merges;
    282     HashSet<size_t> usedNewOrdinals;
    283     for (size_t i = 0; i < oldList.size(); ++i) {
    284         if (oldMap[i].first) {
    285             if (!usedNewOrdinals.contains(oldMap[i].second)) {
    286                 usedNewOrdinals.add(oldMap[i].second);
    287                 continue;
    288             }
    289             oldMap[i].first = 0;
    290             oldMap[i].second = 0;
    291         }
    292 
    293         // Always match <head> and <body> tags with each other - we can't remove them from the DOM
    294         // upon patching.
    295         if (oldList[i]->m_node->hasTagName(headTag)) {
    296             oldHead = oldList[i].get();
    297             continue;
    298         }
    299         if (oldList[i]->m_node->hasTagName(bodyTag)) {
    300             oldBody = oldList[i].get();
    301             continue;
    302         }
    303 
    304         // Check if this change is between stable nodes. If it is, consider it as "modified".
    305         if (!m_unusedNodesMap.contains(oldList[i]->m_sha1) && (!i || oldMap[i - 1].first) && (i == oldMap.size() - 1 || oldMap[i + 1].first)) {
    306             size_t anchorCandidate = i ? oldMap[i - 1].second + 1 : 0;
    307             size_t anchorAfter = i == oldMap.size() - 1 ? anchorCandidate + 1 : oldMap[i + 1].second;
    308             if (anchorAfter - anchorCandidate == 1 && anchorCandidate < newList.size())
    309                 merges.set(newList[anchorCandidate].get(), oldList[i].get());
    310             else {
    311                 removeChild(oldList[i].get(), ec);
    312                 if (ec)
    313                     return;
    314             }
    315         } else {
    316             removeChild(oldList[i].get(), ec);
    317             if (ec)
    318                 return;
    319         }
    320     }
    321 
    322     // Mark retained nodes as used, do not reuse node more than once.
    323     HashSet<size_t> usedOldOrdinals;
    324     for (size_t i = 0; i < newList.size(); ++i) {
    325         if (!newMap[i].first)
    326             continue;
    327         size_t oldOrdinal = newMap[i].second;
    328         if (usedOldOrdinals.contains(oldOrdinal)) {
    329             // Do not map node more than once
    330             newMap[i].first = 0;
    331             newMap[i].second = 0;
    332             continue;
    333         }
    334         usedOldOrdinals.add(oldOrdinal);
    335         markNodeAsUsed(newMap[i].first);
    336     }
    337 
    338     // Mark <head> and <body> nodes for merge.
    339     if (oldHead || oldBody) {
    340         for (size_t i = 0; i < newList.size(); ++i) {
    341             if (oldHead && newList[i]->m_node->hasTagName(headTag))
    342                 merges.set(newList[i].get(), oldHead);
    343             if (oldBody && newList[i]->m_node->hasTagName(bodyTag))
    344                 merges.set(newList[i].get(), oldBody);
    345         }
    346     }
    347 
    348     // 2. Patch nodes marked for merge.
    349     for (HashMap<Digest*, Digest*>::iterator it = merges.begin(); it != merges.end(); ++it) {
    350         innerPatchNode(it->second, it->first, ec);
    351         if (ec)
    352             return;
    353     }
    354 
    355     // 3. Insert missing nodes.
    356     for (size_t i = 0; i < newMap.size(); ++i) {
    357         if (newMap[i].first || merges.contains(newList[i].get()))
    358             continue;
    359 
    360         ExceptionCode ec = 0;
    361         insertBefore(parentNode, newList[i].get(), parentNode->childNode(i), ec);
    362         if (ec)
    363             return;
    364     }
    365 
    366     // 4. Then put all nodes that retained into their slots (sort by new index).
    367     for (size_t i = 0; i < oldMap.size(); ++i) {
    368         if (!oldMap[i].first)
    369             continue;
    370         RefPtr<Node> node = oldMap[i].first->m_node;
    371         Node* anchorNode = parentNode->childNode(oldMap[i].second);
    372         if (node.get() == anchorNode)
    373             continue;
    374         if (node->hasTagName(bodyTag) || node->hasTagName(headTag))
    375             continue; // Never move head or body, move the rest of the nodes around them.
    376 
    377         parentNode->insertBefore(node, anchorNode, ec);
    378         if (ec)
    379             return;
    380     }
    381 }
    382 
    383 static void addStringToSHA1(SHA1& sha1, const String& string)
    384 {
    385     CString cString = string.utf8();
    386     sha1.addBytes(reinterpret_cast<const uint8_t*>(cString.data()), cString.length());
    387 }
    388 
    389 PassOwnPtr<DOMEditor::Digest> DOMEditor::createDigest(Node* node, UnusedNodesMap* unusedNodesMap)
    390 {
    391     Digest* digest = new Digest(node);
    392 
    393     SHA1 sha1;
    394 
    395     Node::NodeType nodeType = node->nodeType();
    396     sha1.addBytes(reinterpret_cast<const uint8_t*>(&nodeType), sizeof(nodeType));
    397     addStringToSHA1(sha1, node->nodeName());
    398     addStringToSHA1(sha1, node->nodeValue());
    399 
    400     if (node->nodeType() == Node::ELEMENT_NODE) {
    401         Node* child = node->firstChild();
    402         while (child) {
    403             OwnPtr<Digest> childInfo = createDigest(child, unusedNodesMap);
    404             addStringToSHA1(sha1, childInfo->m_sha1);
    405             child = child->nextSibling();
    406             digest->m_children.append(childInfo.release());
    407         }
    408         Element* element = static_cast<Element*>(node);
    409 
    410         if (element->hasAttributesWithoutUpdate()) {
    411             size_t numAttrs = element->attributeCount();
    412             SHA1 attrsSHA1;
    413             for (size_t i = 0; i < numAttrs; ++i) {
    414                 const Attribute* attribute = element->attributeItem(i);
    415                 addStringToSHA1(attrsSHA1, attribute->name().toString());
    416                 addStringToSHA1(attrsSHA1, attribute->value());
    417             }
    418             Vector<uint8_t, 20> attrsHash;
    419             attrsSHA1.computeHash(attrsHash);
    420             digest->m_attrsSHA1 = base64Encode(reinterpret_cast<const char*>(attrsHash.data()), 10);
    421             addStringToSHA1(sha1, digest->m_attrsSHA1);
    422         }
    423     }
    424 
    425     Vector<uint8_t, 20> hash;
    426     sha1.computeHash(hash);
    427     digest->m_sha1 = base64Encode(reinterpret_cast<const char*>(hash.data()), 10);
    428     if (unusedNodesMap)
    429         unusedNodesMap->add(digest->m_sha1, digest);
    430     return adoptPtr(digest);
    431 }
    432 
    433 void DOMEditor::insertBefore(ContainerNode* parentNode, Digest* digest, Node* anchor, ExceptionCode& ec)
    434 {
    435     parentNode->insertBefore(digest->m_node, anchor, ec);
    436     markNodeAsUsed(digest);
    437 }
    438 
    439 void DOMEditor::removeChild(Digest* oldDigest, ExceptionCode& ec)
    440 {
    441     RefPtr<Node> oldNode = oldDigest->m_node;
    442     oldNode->parentNode()->removeChild(oldNode.get(), ec);
    443 
    444     // Diff works within levels. In order not to lose the node identity when user
    445     // prepends his HTML with "<div>" (i.e. all nodes are shifted to the next nested level),
    446     // prior to dropping the original node on the floor, check whether new DOM has a digest
    447     // with matching sha1. If it does, replace it with the original DOM chunk. Chances are
    448     // high that it will get merged back into the original DOM during the further patching.
    449 
    450     UnusedNodesMap::iterator it = m_unusedNodesMap.find(oldDigest->m_sha1);
    451     if (it != m_unusedNodesMap.end()) {
    452         Digest* newDigest = it->second;
    453         Node* newNode = newDigest->m_node;
    454         newNode->parentNode()->replaceChild(oldNode, newNode, ec);
    455         newDigest->m_node = oldNode.get();
    456         markNodeAsUsed(newDigest);
    457         return;
    458     }
    459 
    460     for (size_t i = 0; i < oldDigest->m_children.size(); ++i)
    461         removeChild(oldDigest->m_children[i].get(), ec);
    462 }
    463 
    464 void DOMEditor::markNodeAsUsed(Digest* digest)
    465 {
    466     Deque<Digest*> queue;
    467     queue.append(digest);
    468     while (!queue.isEmpty()) {
    469         Digest* first = queue.takeFirst();
    470         m_unusedNodesMap.remove(first->m_sha1);
    471         for (size_t i = 0; i < first->m_children.size(); ++i)
    472             queue.append(first->m_children[i].get());
    473     }
    474 }
    475 
    476 #ifdef DEBUG_DOM_EDITOR
    477 static String nodeName(Node* node)
    478 {
    479     if (node->document()->isXHTMLDocument())
    480          return node->nodeName();
    481     return node->nodeName().lower();
    482 }
    483 
    484 void DOMEditor::dumpMap(const ResultMap& map, const String& name)
    485 {
    486     fprintf(stderr, "\n\n");
    487     for (size_t i = 0; i < map.size(); ++i)
    488         fprintf(stderr, "%s[%lu]: %s (%p) - [%lu]\n", name.utf8().data(), i, map[i].first ? nodeName(map[i].first->m_node).utf8().data() : "", map[i].first, map[i].second);
    489 }
    490 #endif
     301bool DOMEditor::insertBefore(Node* parentNode, Node* node, Node* anchorNode, ErrorString* errorString)
     302{
     303    return m_history->perform(adoptPtr(new InsertBeforeAction(parentNode, node, anchorNode)), errorString);
     304}
     305
     306bool DOMEditor::removeChild(Node* parentNode, Node* node, ErrorString* errorString)
     307{
     308    return m_history->perform(adoptPtr(new RemoveChildAction(parentNode, node)), errorString);
     309}
     310
     311bool DOMEditor::setAttribute(Element* element, const String& name, const String& value, ErrorString* errorString)
     312{
     313    return m_history->perform(adoptPtr(new SetAttributeAction(element, name, value)), errorString);
     314}
     315
     316bool DOMEditor::removeAttribute(Element* element, const String& name, ErrorString* errorString)
     317{
     318    return m_history->perform(adoptPtr(new RemoveAttributeAction(element, name)), errorString);
     319}
     320
     321bool DOMEditor::setOuterHTML(Node* node, const String& html, Node** newNode, ErrorString* errorString)
     322{
     323    OwnPtr<SetOuterHTMLAction> action = adoptPtr(new SetOuterHTMLAction(node, html));
     324    SetOuterHTMLAction* rawAction = action.get();
     325    bool result = m_history->perform(action.release(), errorString);
     326    if (result)
     327        *newNode = rawAction->newNode();
     328    return result;
     329}
     330
     331bool DOMEditor::replaceWholeText(Text* textNode, const String& text, ErrorString* errorString)
     332{
     333    return m_history->perform(adoptPtr(new ReplaceWholeTextAction(textNode, text)), errorString);
     334}
    491335
    492336} // namespace WebCore
  • trunk/Source/WebCore/inspector/DOMEditor.h

    r107242 r107257  
    3232#define DOMEditor_h
    3333
    34 #include "ExceptionCode.h"
    35 
    36 #include <wtf/HashMap.h>
    37 #include <wtf/OwnPtr.h>
    38 #include <wtf/PassOwnPtr.h>
    39 #include <wtf/Vector.h>
    4034#include <wtf/text/WTFString.h>
    4135
    4236namespace WebCore {
    4337
    44 class ContainerNode;
    45 class Document;
    46 class NamedNodeMap;
     38class Element;
     39class InspectorHistory;
    4740class Node;
     41class Text;
    4842
    4943#if ENABLE(INSPECTOR)
    5044
     45typedef String ErrorString;
     46
    5147class DOMEditor {
     48    WTF_MAKE_NONCOPYABLE(DOMEditor);
    5249public:
    53     explicit DOMEditor(Document*);
    54     virtual ~DOMEditor();
     50    explicit DOMEditor(InspectorHistory*);
     51    ~DOMEditor();
    5552
    56     void patchDocument(const String& markup);
    57     Node* patchNode(Node*, const String& markup, ExceptionCode&);
     53    bool insertBefore(Node* parentNode, Node*, Node* anchorNode, ErrorString*);
     54    bool removeChild(Node* parentNode, Node*, ErrorString*);
     55    bool setAttribute(Element*, const String& name, const String& value, ErrorString*);
     56    bool removeAttribute(Element*, const String& name, ErrorString*);
     57    bool setOuterHTML(Node*, const String& html, Node** newNode, ErrorString*);
     58    bool replaceWholeText(Text*, const String& text, ErrorString*);
    5859
    5960private:
    60     struct Digest;
    61     typedef Vector<pair<Digest*, size_t> > ResultMap;
    62     typedef HashMap<String, Digest*> UnusedNodesMap;
     61    class DOMAction;
     62    class RemoveChildAction;
     63    class InsertBeforeAction;
     64    class RemoveAttributeAction;
     65    class SetAttributeAction;
     66    class SetOuterHTMLAction;
     67    class ReplaceWholeTextAction;
    6368
    64     void innerPatchNode(Digest* oldNode, Digest* newNode, ExceptionCode&);
    65     std::pair<ResultMap, ResultMap> diff(const Vector<OwnPtr<Digest> >& oldChildren, const Vector<OwnPtr<Digest> >& newChildren);
    66     void innerPatchChildren(ContainerNode*, const Vector<OwnPtr<Digest> >& oldChildren, const Vector<OwnPtr<Digest> >& newChildren, ExceptionCode&);
    67     PassOwnPtr<Digest> createDigest(Node*, UnusedNodesMap*);
    68     void insertBefore(ContainerNode*, Digest*, Node* anchor, ExceptionCode&);
    69     void removeChild(Digest*, ExceptionCode&);
    70     void markNodeAsUsed(Digest*);
    71 #ifdef DEBUG_DOM_EDITOR
    72     void dumpMap(const ResultMap&, const String& name);
    73 #endif
    74 
    75     Document* m_document;
    76 
    77     UnusedNodesMap m_unusedNodesMap;
     69    InspectorHistory* m_history;
    7870};
    7971
  • trunk/Source/WebCore/inspector/DOMPatchSupport.cpp

    r107256 r107257  
    3030
    3131#include "config.h"
    32 #include "DOMEditor.h"
     32#include "DOMPatchSupport.h"
    3333
    3434#if ENABLE(INSPECTOR)
     
    5858using HTMLNames::htmlTag;
    5959
    60 struct DOMEditor::Digest {
     60struct DOMPatchSupport::Digest {
    6161    explicit Digest(Node* node) : m_node(node) { }
    6262
     
    6767};
    6868
    69 DOMEditor::DOMEditor(Document* document) : m_document(document) { }
    70 
    71 DOMEditor::~DOMEditor() { }
    72 
    73 void DOMEditor::patchDocument(const String& markup)
     69DOMPatchSupport::DOMPatchSupport(Document* document) : m_document(document) { }
     70
     71DOMPatchSupport::~DOMPatchSupport() { }
     72
     73void DOMPatchSupport::patchDocument(const String& markup)
    7474{
    7575    RefPtr<HTMLDocument> newDocument = HTMLDocument::create(0, KURL());
     
    9191}
    9292
    93 Node* DOMEditor::patchNode(Node* node, const String& markup, ExceptionCode& ec)
     93Node* DOMPatchSupport::patchNode(Node* node, const String& markup, ExceptionCode& ec)
    9494{
    9595    // Don't parse <html> as a fragment.
     
    136136}
    137137
    138 void DOMEditor::innerPatchNode(Digest* oldDigest, Digest* newDigest, ExceptionCode& ec)
     138void DOMPatchSupport::innerPatchNode(Digest* oldDigest, Digest* newDigest, ExceptionCode& ec)
    139139{
    140140    if (oldDigest->m_sha1 == newDigest->m_sha1)
     
    181181}
    182182
    183 pair<DOMEditor::ResultMap, DOMEditor::ResultMap>
    184 DOMEditor::diff(const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList)
     183pair<DOMPatchSupport::ResultMap, DOMPatchSupport::ResultMap>
     184DOMPatchSupport::diff(const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList)
    185185{
    186186    ResultMap newMap(newList.size());
     
    261261    }
    262262
    263 #ifdef DEBUG_DOM_EDITOR
     263#ifdef DEBUG_DOM_PATCH_SUPPORT
    264264    dumpMap(oldMap, "OLD");
    265265    dumpMap(newMap, "NEW");
     
    269269}
    270270
    271 void DOMEditor::innerPatchChildren(ContainerNode* parentNode, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionCode& ec)
     271void DOMPatchSupport::innerPatchChildren(ContainerNode* parentNode, const Vector<OwnPtr<Digest> >& oldList, const Vector<OwnPtr<Digest> >& newList, ExceptionCode& ec)
    272272{
    273273    pair<ResultMap, ResultMap> resultMaps = diff(oldList, newList);
     
    387387}
    388388
    389 PassOwnPtr<DOMEditor::Digest> DOMEditor::createDigest(Node* node, UnusedNodesMap* unusedNodesMap)
     389PassOwnPtr<DOMPatchSupport::Digest> DOMPatchSupport::createDigest(Node* node, UnusedNodesMap* unusedNodesMap)
    390390{
    391391    Digest* digest = new Digest(node);
     
    431431}
    432432
    433 void DOMEditor::insertBefore(ContainerNode* parentNode, Digest* digest, Node* anchor, ExceptionCode& ec)
     433void DOMPatchSupport::insertBefore(ContainerNode* parentNode, Digest* digest, Node* anchor, ExceptionCode& ec)
    434434{
    435435    parentNode->insertBefore(digest->m_node, anchor, ec);
     
    437437}
    438438
    439 void DOMEditor::removeChild(Digest* oldDigest, ExceptionCode& ec)
     439void DOMPatchSupport::removeChild(Digest* oldDigest, ExceptionCode& ec)
    440440{
    441441    RefPtr<Node> oldNode = oldDigest->m_node;
     
    462462}
    463463
    464 void DOMEditor::markNodeAsUsed(Digest* digest)
     464void DOMPatchSupport::markNodeAsUsed(Digest* digest)
    465465{
    466466    Deque<Digest*> queue;
     
    474474}
    475475
    476 #ifdef DEBUG_DOM_EDITOR
     476#ifdef DEBUG_DOM_PATCH_SUPPORT
    477477static String nodeName(Node* node)
    478478{
     
    482482}
    483483
    484 void DOMEditor::dumpMap(const ResultMap& map, const String& name)
     484void DOMPatchSupport::dumpMap(const ResultMap& map, const String& name)
    485485{
    486486    fprintf(stderr, "\n\n");
  • trunk/Source/WebCore/inspector/DOMPatchSupport.h

    r107256 r107257  
    2929 */
    3030
    31 #ifndef DOMEditor_h
    32 #define DOMEditor_h
     31#ifndef DOMPatchSupport_h
     32#define DOMPatchSupport_h
    3333
    3434#include "ExceptionCode.h"
     
    4949#if ENABLE(INSPECTOR)
    5050
    51 class DOMEditor {
     51class DOMPatchSupport {
     52    WTF_MAKE_NONCOPYABLE(DOMPatchSupport);
    5253public:
    53     explicit DOMEditor(Document*);
    54     virtual ~DOMEditor();
     54    explicit DOMPatchSupport(Document*);
     55    virtual ~DOMPatchSupport();
    5556
    5657    void patchDocument(const String& markup);
     
    6970    void removeChild(Digest*, ExceptionCode&);
    7071    void markNodeAsUsed(Digest*);
    71 #ifdef DEBUG_DOM_EDITOR
     72#ifdef DEBUG_DOM_PATCH_SUPPORT
    7273    void dumpMap(const ResultMap&, const String& name);
    7374#endif
     
    8283} // namespace WebCore
    8384
    84 #endif // !defined(DOMEditor_h)
     85#endif // !defined(DOMPatchSupport_h)
  • trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp

    r107217 r107257  
    4949#include "DOMEditor.h"
    5050#include "DOMNodeHighlighter.h"
     51#include "DOMPatchSupport.h"
    5152#include "DOMWindow.h"
    5253#include "Document.h"
     
    6768#include "InspectorClient.h"
    6869#include "InspectorFrontend.h"
     70#include "InspectorHistory.h"
    6971#include "InspectorPageAgent.h"
    7072#include "InspectorState.h"
     
    178180}
    179181
    180 class InspectorDOMAgent::DOMAction : public InspectorHistory::Action {
    181 public:
    182     DOMAction(const String& name) : InspectorHistory::Action(name) { }
    183 
    184     virtual bool perform(ErrorString* errorString)
    185     {
    186         ExceptionCode ec = 0;
    187         bool result = perform(ec);
    188         if (ec) {
    189             ExceptionCodeDescription description(ec);
    190             *errorString = description.name;
    191         }
    192         return result && !ec;
    193     }
    194 
    195     virtual bool undo(ErrorString* errorString)
    196     {
    197         ExceptionCode ec = 0;
    198         bool result = undo(ec);
    199         if (ec) {
    200             ExceptionCodeDescription description(ec);
    201             *errorString = description.name;
    202         }
    203         return result && !ec;
    204     }
    205 
    206     virtual bool perform(ExceptionCode&) = 0;
    207 
    208     virtual bool undo(ExceptionCode&) = 0;
    209 
    210 private:
    211     RefPtr<Node> m_parentNode;
    212     RefPtr<Node> m_node;
    213     RefPtr<Node> m_anchorNode;
    214 };
    215 
    216 class InspectorDOMAgent::RemoveChildAction : public InspectorDOMAgent::DOMAction {
    217     WTF_MAKE_NONCOPYABLE(RemoveChildAction);
    218 public:
    219     RemoveChildAction(Node* parentNode, Node* node)
    220         : InspectorDOMAgent::DOMAction("RemoveChild")
    221         , m_parentNode(parentNode)
    222         , m_node(node)
    223     {
    224     }
    225 
    226     virtual bool perform(ExceptionCode& ec)
    227     {
    228         m_anchorNode = m_node->nextSibling();
    229         return m_parentNode->removeChild(m_node.get(), ec);
    230     }
    231 
    232     virtual bool undo(ExceptionCode& ec)
    233     {
    234         return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);
    235     }
    236 
    237 private:
    238     RefPtr<Node> m_parentNode;
    239     RefPtr<Node> m_node;
    240     RefPtr<Node> m_anchorNode;
    241 };
    242 
    243 class InspectorDOMAgent::InsertBeforeAction : public InspectorDOMAgent::DOMAction {
    244     WTF_MAKE_NONCOPYABLE(InsertBeforeAction);
    245 public:
    246     InsertBeforeAction(Node* parentNode, Node* node, Node* anchorNode)
    247         : InspectorDOMAgent::DOMAction("InsertBefore")
    248         , m_parentNode(parentNode)
    249         , m_node(node)
    250         , m_anchorNode(anchorNode)
    251     {
    252     }
    253 
    254     virtual bool perform(ExceptionCode& ec)
    255     {
    256         if (m_node->parentNode()) {
    257             m_removeChildAction = adoptPtr(new RemoveChildAction(m_node->parentNode(), m_node.get()));
    258             if (!m_removeChildAction->perform(ec))
    259                 return false;
    260         }
    261         return m_parentNode->insertBefore(m_node.get(), m_anchorNode.get(), ec);
    262     }
    263 
    264     virtual bool undo(ExceptionCode& ec)
    265     {
    266         if (m_removeChildAction)
    267             return m_removeChildAction->undo(ec);
    268 
    269         return m_parentNode->removeChild(m_node.get(), ec);
    270     }
    271 
    272 private:
    273     RefPtr<Node> m_parentNode;
    274     RefPtr<Node> m_node;
    275     RefPtr<Node> m_anchorNode;
    276     OwnPtr<RemoveChildAction> m_removeChildAction;
    277 };
    278 
    279 class InspectorDOMAgent::RemoveAttributeAction : public InspectorDOMAgent::DOMAction {
    280     WTF_MAKE_NONCOPYABLE(RemoveAttributeAction);
    281 public:
    282     RemoveAttributeAction(Element* element, const String& name)
    283         : InspectorDOMAgent::DOMAction("RemoveAttribute")
    284         , m_element(element)
    285         , m_name(name)
    286     {
    287     }
    288 
    289     virtual bool perform(ExceptionCode&)
    290     {
    291         m_value = m_element->getAttribute(m_name);
    292         m_element->removeAttribute(m_name);
    293         return true;
    294     }
    295 
    296     virtual bool undo(ExceptionCode& ec)
    297     {
    298         m_element->setAttribute(m_name, m_value, ec);
    299         return true;
    300     }
    301 
    302 private:
    303     RefPtr<Element> m_element;
    304     String m_name;
    305     String m_value;
    306 };
    307 
    308 class InspectorDOMAgent::SetAttributeAction : public InspectorDOMAgent::DOMAction {
    309     WTF_MAKE_NONCOPYABLE(SetAttributeAction);
    310 public:
    311     SetAttributeAction(Element* element, const String& name, const String& value)
    312         : InspectorDOMAgent::DOMAction("SetAttribute")
    313         , m_element(element)
    314         , m_name(name)
    315         , m_value(value)
    316         , m_hadAttribute(false)
    317     {
    318     }
    319 
    320     virtual bool perform(ExceptionCode& ec)
    321     {
    322         m_hadAttribute = m_element->hasAttribute(m_name);
    323         if (m_hadAttribute)
    324             m_oldValue = m_element->getAttribute(m_name);
    325         m_element->setAttribute(m_name, m_value, ec);
    326         return !ec;
    327     }
    328 
    329     virtual bool undo(ExceptionCode& ec)
    330     {
    331         if (m_hadAttribute)
    332             m_element->setAttribute(m_name, m_oldValue, ec);
    333         else
    334             m_element->removeAttribute(m_name);
    335         return true;
    336     }
    337 
    338 private:
    339     RefPtr<Element> m_element;
    340     String m_name;
    341     String m_value;
    342     bool m_hadAttribute;
    343     String m_oldValue;
    344 };
    345 
    346 class InspectorDOMAgent::SetOuterHTMLAction : public InspectorDOMAgent::DOMAction {
    347     WTF_MAKE_NONCOPYABLE(SetOuterHTMLAction);
    348 public:
    349     SetOuterHTMLAction(Node* node, const String& html)
    350         : InspectorDOMAgent::DOMAction("SetOuterHTML")
    351         , m_node(node)
    352         , m_nextSibling(node->nextSibling())
    353         , m_html(html)
    354         , m_newNode(0)
    355     {
    356     }
    357 
    358     virtual bool perform(ExceptionCode& ec)
    359     {
    360         m_oldHTML = createMarkup(m_node.get());
    361         DOMEditor domEditor(m_node->ownerDocument());
    362         m_newNode = domEditor.patchNode(m_node.get(), m_html, ec);
    363         return !ec;
    364     }
    365 
    366     virtual bool undo(ExceptionCode& ec)
    367     {
    368         DOMEditor domEditor(m_newNode->ownerDocument());
    369         Node* node = domEditor.patchNode(m_newNode, m_oldHTML, ec);
    370         if (ec || !node)
    371             return false;
    372         // HTML editing could have produced extra nodes. Remove them if necessary.
    373         node = node->nextSibling();
    374 
    375         while (!ec && node && node != m_nextSibling.get()) {
    376             Node* nodeToRemove = node;
    377             node = node->nextSibling();
    378             nodeToRemove->remove(ec);
    379         }
    380         return !ec;
    381     }
    382 
    383     Node* newNode()
    384     {
    385         return m_newNode;
    386     }
    387 
    388 private:
    389     RefPtr<Node> m_node;
    390     RefPtr<Node> m_nextSibling;
    391     String m_html;
    392     String m_oldHTML;
    393     Node* m_newNode;
    394 };
    395 
    396 class InspectorDOMAgent::ReplaceWholeTextAction : public InspectorDOMAgent::DOMAction {
    397     WTF_MAKE_NONCOPYABLE(ReplaceWholeTextAction);
    398 public:
    399     ReplaceWholeTextAction(Text* textNode, const String& text)
    400         : DOMAction("ReplaceWholeText")
    401         , m_textNode(textNode)
    402         , m_text(text)
    403     {
    404     }
    405 
    406     virtual bool perform(ExceptionCode& ec)
    407     {
    408         m_oldText = m_textNode->wholeText();
    409         m_textNode->replaceWholeText(m_text, ec);
    410         return true;
    411     }
    412 
    413     virtual bool undo(ExceptionCode& ec)
    414     {
    415         m_textNode->replaceWholeText(m_oldText, ec);
    416         return true;
    417     }
    418 
    419 private:
    420     RefPtr<Text> m_textNode;
    421     String m_text;
    422     String m_oldText;
    423 };
    424 
    425182InspectorDOMAgent::InspectorDOMAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorClient* client, InspectorState* inspectorState, InjectedScriptManager* injectedScriptManager)
    426183    : InspectorBaseAgent<InspectorDOMAgent>("DOM", instrumentingAgents, inspectorState)
     
    432189    , m_lastNodeId(1)
    433190    , m_searchingForNode(false)
    434     , m_history(adoptPtr(new InspectorHistory()))
    435191{
    436192}
     
    446202{
    447203    ASSERT(!m_frontend);
     204    m_history = adoptPtr(new InspectorHistory());
     205    m_domEditor = adoptPtr(new DOMEditor(m_history.get()));
     206
    448207    m_frontend = frontend->dom();
    449208    m_instrumentingAgents->setInspectorDOMAgent(this);
     
    457216{
    458217    ASSERT(m_frontend);
     218
     219    m_history.clear();
     220    m_domEditor.clear();
    459221    setSearchingForNode(false, 0);
    460222
     
    500262void InspectorDOMAgent::reset()
    501263{
    502     m_history->reset();
     264    if (m_history)
     265        m_history->reset();
    503266    m_searchResults.clear();
    504267    discardBindings();
     
    766529        return;
    767530
    768     m_history->perform(adoptPtr(new SetAttributeAction(element, name, value)), errorString);
     531    m_domEditor->setAttribute(element, name, value, errorString);
    769532    m_history->markUndoableState();
    770533}
     
    797560    Element* childElement = toElement(child);
    798561    if (!childElement->hasAttributes() && name) {
    799         m_history->perform(adoptPtr(new RemoveAttributeAction(element, *name)), errorString);
     562        m_domEditor->removeAttribute(element, *name, errorString);
     563        m_history->markUndoableState();
    800564        return;
    801565    }
     
    807571        const Attribute* attribute = childElement->attributeItem(i);
    808572        foundOriginalAttribute = foundOriginalAttribute || (name && attribute->name().toString() == *name);
    809         if (!m_history->perform(adoptPtr(new SetAttributeAction(element, attribute->name().toString(), attribute->value())), errorString))
     573        if (!m_domEditor->setAttribute(element, attribute->name().toString(), attribute->value(), errorString))
    810574            return;
    811575    }
    812576
    813577    if (!foundOriginalAttribute && name && !name->stripWhiteSpace().isEmpty())
    814         m_history->perform(adoptPtr(new RemoveAttributeAction(element, *name)), errorString);
     578        m_domEditor->removeAttribute(element, *name, errorString);
    815579
    816580    m_history->markUndoableState();
     
    823587        return;
    824588
    825     m_history->perform(adoptPtr(new RemoveAttributeAction(element, name)), errorString);
     589    m_domEditor->removeAttribute(element, name, errorString);
    826590    m_history->markUndoableState();
    827591}
     
    839603    }
    840604
    841     m_history->perform(adoptPtr(new RemoveChildAction(parentNode, node)), errorString);
     605    m_domEditor->removeChild(parentNode, node, errorString);
    842606    m_history->markUndoableState();
    843607}
     
    862626    Node* child;
    863627    while ((child = oldNode->firstChild())) {
    864         if (!m_history->perform(adoptPtr(new InsertBeforeAction(newElem.get(), child, 0)), errorString))
     628        if (!m_domEditor->insertBefore(newElem.get(), child, 0, errorString))
    865629            return;
    866630    }
     
    868632    // Replace the old node with the new node
    869633    ContainerNode* parent = oldNode->parentNode();
    870     if (!m_history->perform(adoptPtr(new InsertBeforeAction(parent, newElem.get(), oldNode->nextSibling())), errorString))
    871         return;
    872     if (!m_history->perform(adoptPtr(new RemoveChildAction(parent, oldNode)), errorString))
     634    if (!m_domEditor->insertBefore(parent, newElem.get(), oldNode->nextSibling(), errorString))
     635        return;
     636    if (!m_domEditor->removeChild(parent, oldNode, errorString))
    873637        return;
    874638    m_history->markUndoableState();
     
    891655{
    892656    if (!nodeId) {
    893         DOMEditor domEditor(m_document.get());
    894         domEditor.patchDocument(outerHTML);
     657        DOMPatchSupport domPatchSupport(m_document.get());
     658        domPatchSupport.patchDocument(outerHTML);
    895659        return;
    896660    }
     
    906670    }
    907671
    908     DOMEditor domEditor(document);
    909 
    910     OwnPtr<SetOuterHTMLAction> action = adoptPtr(new SetOuterHTMLAction(node, outerHTML));
    911     SetOuterHTMLAction* rawAction = action.get();
    912672    Node* newNode = 0;
    913     if (!m_history->perform(action.release(), errorString))
     673    if (!m_domEditor->setOuterHTML(node, outerHTML, &newNode, errorString))
    914674        return;
    915675    m_history->markUndoableState();
    916 
    917     newNode = rawAction->newNode();
    918676
    919677    if (!newNode) {
     
    940698    }
    941699
    942     m_history->perform(adoptPtr(new ReplaceWholeTextAction(static_cast<Text*>(node), value)), errorString);
     700    m_domEditor->replaceWholeText(static_cast<Text*>(node), value, errorString);
    943701}
    944702
     
    12981056    }
    12991057
    1300     if (!m_history->perform(adoptPtr(new InsertBeforeAction(targetElement, node, anchorNode)), errorString))
     1058    if (!m_domEditor->insertBefore(targetElement, node, anchorNode, errorString))
    13011059        return;
    13021060    m_history->markUndoableState();
  • trunk/Source/WebCore/inspector/InspectorDOMAgent.h

    r106953 r107257  
    3636#include "InspectorBaseAgent.h"
    3737#include "InspectorFrontend.h"
    38 #include "InspectorHistory.h"
    3938#include "InspectorValues.h"
    4039#include "Timer.h"
     
    5352class ContainerNode;
    5453class CharacterData;
     54class DOMEditor;
    5555class Document;
    5656class Element;
     
    5858class GraphicsContext;
    5959class InspectorClient;
    60 class InspectorDOMAgent;
    6160class InspectorFrontend;
     61class InspectorHistory;
    6262class InspectorPageAgent;
    6363class IntRect;
     
    194194
    195195private:
    196     class DOMAction;
    197     class RemoveChildAction;
    198     class InsertBeforeAction;
    199     class RemoveAttributeAction;
    200     class SetAttributeAction;
    201     class SetOuterHTMLAction;
    202     class ReplaceWholeTextAction;
    203 
    204196    InspectorDOMAgent(InstrumentingAgents*, InspectorPageAgent*, InspectorClient*, InspectorState*, InjectedScriptManager*);
    205197
     
    255247    bool m_searchingForNode;
    256248    OwnPtr<InspectorHistory> m_history;
     249    OwnPtr<DOMEditor> m_domEditor;
    257250};
    258251
  • trunk/Source/WebCore/inspector/InspectorPageAgent.cpp

    r105600 r107257  
    4343#include "Cookie.h"
    4444#include "CookieJar.h"
    45 #include "DOMEditor.h"
     45#include "DOMPatchSupport.h"
    4646#include "Document.h"
    4747#include "DocumentLoader.h"
     
    572572        return;
    573573    }
    574     DOMEditor editor(document);
    575     editor.patchDocument(html);
     574    DOMPatchSupport patcher(document);
     575    patcher.patchDocument(html);
    576576}
    577577
Note: See TracChangeset for help on using the changeset viewer.