Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <stdio.h> // for printf
8 #include "SplitElementTxn.h"
9 #include "nsAString.h"
10 #include "nsDebug.h" // for NS_ASSERTION, etc
11 #include "nsEditor.h" // for nsEditor
12 #include "nsError.h" // for NS_ERROR_NOT_INITIALIZED, etc
13 #include "nsIDOMCharacterData.h" // for nsIDOMCharacterData
14 #include "nsIDOMNode.h" // for nsIDOMNode
15 #include "nsIEditor.h" // for nsEditor::DebugDumpContent, etc
16 #include "nsISelection.h" // for nsISelection
17 #include "nsISupportsUtils.h" // for NS_ADDREF
19 // note that aEditor is not refcounted
20 SplitElementTxn::SplitElementTxn()
21 : EditTxn()
22 {
23 }
25 NS_IMPL_CYCLE_COLLECTION_INHERITED(SplitElementTxn, EditTxn,
26 mParent,
27 mNewLeftNode)
29 NS_IMPL_ADDREF_INHERITED(SplitElementTxn, EditTxn)
30 NS_IMPL_RELEASE_INHERITED(SplitElementTxn, EditTxn)
31 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SplitElementTxn)
32 NS_INTERFACE_MAP_END_INHERITING(EditTxn)
34 NS_IMETHODIMP SplitElementTxn::Init(nsEditor *aEditor,
35 nsIDOMNode *aNode,
36 int32_t aOffset)
37 {
38 NS_ASSERTION(aEditor && aNode, "bad args");
39 if (!aEditor || !aNode) { return NS_ERROR_NOT_INITIALIZED; }
41 mEditor = aEditor;
42 mExistingRightNode = do_QueryInterface(aNode);
43 mOffset = aOffset;
44 return NS_OK;
45 }
47 NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
48 {
49 NS_ASSERTION(mExistingRightNode && mEditor, "bad state");
50 if (!mExistingRightNode || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
52 // create a new node
53 nsresult result = mExistingRightNode->CloneNode(false, 1, getter_AddRefs(mNewLeftNode));
54 NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewLeftNode)), "could not create element.");
55 NS_ENSURE_SUCCESS(result, result);
56 NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NULL_POINTER);
57 mEditor->MarkNodeDirty(mExistingRightNode);
59 // get the parent node
60 result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent));
61 NS_ENSURE_SUCCESS(result, result);
62 NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER);
64 // insert the new node
65 result = mEditor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent);
66 if (mNewLeftNode) {
67 bool bAdjustSelection;
68 mEditor->ShouldTxnSetSelection(&bAdjustSelection);
69 if (bAdjustSelection)
70 {
71 nsCOMPtr<nsISelection> selection;
72 result = mEditor->GetSelection(getter_AddRefs(selection));
73 NS_ENSURE_SUCCESS(result, result);
74 NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
75 result = selection->Collapse(mNewLeftNode, mOffset);
76 }
77 else
78 {
79 // do nothing - dom range gravity will adjust selection
80 }
81 }
82 return result;
83 }
85 NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
86 {
87 NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state");
88 if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) {
89 return NS_ERROR_NOT_INITIALIZED;
90 }
92 // this assumes Do inserted the new node in front of the prior existing node
93 nsCOMPtr<nsINode> rightNode = do_QueryInterface(mExistingRightNode);
94 nsCOMPtr<nsINode> leftNode = do_QueryInterface(mNewLeftNode);
95 nsCOMPtr<nsINode> parent = do_QueryInterface(mParent);
96 NS_ENSURE_TRUE(rightNode && leftNode && parent, NS_ERROR_FAILURE);
97 return mEditor->JoinNodesImpl(rightNode, leftNode, parent);
98 }
100 /* redo cannot simply resplit the right node, because subsequent transactions
101 * on the redo stack may depend on the left node existing in its previous state.
102 */
103 NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
104 {
105 NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state");
106 if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) {
107 return NS_ERROR_NOT_INITIALIZED;
108 }
110 nsresult result;
111 nsCOMPtr<nsIDOMNode>resultNode;
112 // first, massage the existing node so it is in its post-split state
113 nsCOMPtr<nsIDOMCharacterData>rightNodeAsText = do_QueryInterface(mExistingRightNode);
114 if (rightNodeAsText)
115 {
116 nsresult result = rightNodeAsText->DeleteData(0, mOffset);
117 NS_ENSURE_SUCCESS(result, result);
118 }
119 else
120 {
121 nsCOMPtr<nsIDOMNode>child;
122 nsCOMPtr<nsIDOMNode>nextSibling;
123 result = mExistingRightNode->GetFirstChild(getter_AddRefs(child));
124 int32_t i;
125 for (i=0; i<mOffset; i++)
126 {
127 if (NS_FAILED(result)) {return result;}
128 if (!child) {return NS_ERROR_NULL_POINTER;}
129 child->GetNextSibling(getter_AddRefs(nextSibling));
130 result = mExistingRightNode->RemoveChild(child, getter_AddRefs(resultNode));
131 if (NS_SUCCEEDED(result))
132 {
133 result = mNewLeftNode->AppendChild(child, getter_AddRefs(resultNode));
134 }
135 child = do_QueryInterface(nextSibling);
136 }
137 }
138 // second, re-insert the left node into the tree
139 result = mParent->InsertBefore(mNewLeftNode, mExistingRightNode, getter_AddRefs(resultNode));
140 return result;
141 }
144 NS_IMETHODIMP SplitElementTxn::GetTxnDescription(nsAString& aString)
145 {
146 aString.AssignLiteral("SplitElementTxn");
147 return NS_OK;
148 }
150 NS_IMETHODIMP SplitElementTxn::GetNewNode(nsIDOMNode **aNewNode)
151 {
152 NS_ENSURE_TRUE(aNewNode, NS_ERROR_NULL_POINTER);
153 NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NOT_INITIALIZED);
154 *aNewNode = mNewLeftNode;
155 NS_ADDREF(*aNewNode);
156 return NS_OK;
157 }