зеркало из https://github.com/mozilla/gecko-dev.git
fixes for bugs: 16361,12253,15696,15734; r=sfraser
This commit is contained in:
Родитель
69f850d965
Коммит
f5c0eec556
|
@ -25,36 +25,29 @@ EditAggregateTxn::EditAggregateTxn()
|
|||
: EditTxn()
|
||||
{
|
||||
// base class does this: NS_INIT_REFCNT();
|
||||
mChildren = new nsVoidArray();
|
||||
nsresult res = NS_NewISupportsArray(getter_AddRefs(mChildren));
|
||||
NS_POSTCONDITION(NS_SUCCEEDED(res), "EditAggregateTxn failed in constructor");
|
||||
SetTransactionDescriptionID( kTransactionID );
|
||||
/* log description initialized in parent constructor */
|
||||
}
|
||||
|
||||
EditAggregateTxn::~EditAggregateTxn()
|
||||
{
|
||||
if (nsnull!=mChildren)
|
||||
{
|
||||
PRInt32 i;
|
||||
PRInt32 count = mChildren->Count();
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
|
||||
NS_IF_RELEASE(txn);
|
||||
}
|
||||
delete mChildren;
|
||||
}
|
||||
// nsISupportsArray cleans up array for us at destruct time
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::Do(void)
|
||||
{
|
||||
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
|
||||
if (nsnull!=mChildren)
|
||||
if (mChildren)
|
||||
{
|
||||
PRInt32 i;
|
||||
PRInt32 count = mChildren->Count();
|
||||
PRUint32 count;
|
||||
mChildren->Count(&count);
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsITransaction> txn ( do_QueryInterface(isupports) );
|
||||
if (!txn) { return NS_ERROR_NULL_POINTER; }
|
||||
result = txn->Do();
|
||||
if (NS_FAILED(result))
|
||||
|
@ -67,14 +60,17 @@ NS_IMETHODIMP EditAggregateTxn::Do(void)
|
|||
NS_IMETHODIMP EditAggregateTxn::Undo(void)
|
||||
{
|
||||
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
|
||||
if (nsnull!=mChildren)
|
||||
if (mChildren)
|
||||
{
|
||||
PRInt32 i;
|
||||
PRInt32 count = mChildren->Count();
|
||||
PRUint32 count;
|
||||
mChildren->Count(&count);
|
||||
// undo goes through children backwards
|
||||
for (i=count-1; i>=0; i--)
|
||||
{
|
||||
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsITransaction> txn ( do_QueryInterface(isupports) );
|
||||
if (!txn) { return NS_ERROR_NULL_POINTER; }
|
||||
result = txn->Undo();
|
||||
if (NS_FAILED(result))
|
||||
break;
|
||||
|
@ -86,13 +82,16 @@ NS_IMETHODIMP EditAggregateTxn::Undo(void)
|
|||
NS_IMETHODIMP EditAggregateTxn::Redo(void)
|
||||
{
|
||||
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
|
||||
if (nsnull!=mChildren)
|
||||
if (mChildren)
|
||||
{
|
||||
PRInt32 i;
|
||||
PRInt32 count = mChildren->Count();
|
||||
PRUint32 count;
|
||||
mChildren->Count(&count);
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsITransaction> txn ( do_QueryInterface(isupports) );
|
||||
if (!txn) { return NS_ERROR_NULL_POINTER; }
|
||||
result = txn->Redo();
|
||||
if (NS_FAILED(result))
|
||||
break;
|
||||
|
@ -113,13 +112,17 @@ NS_IMETHODIMP EditAggregateTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransa
|
|||
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
|
||||
if (nsnull!=aDidMerge)
|
||||
*aDidMerge=PR_FALSE;
|
||||
if (nsnull!=mChildren)
|
||||
if (mChildren)
|
||||
{
|
||||
PRInt32 count = mChildren->Count();
|
||||
PRInt32 i;
|
||||
PRUint32 count;
|
||||
mChildren->Count(&count);
|
||||
NS_ASSERTION(count>0, "bad count");
|
||||
if (0<count)
|
||||
{
|
||||
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(count-1));
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsITransaction> txn ( do_QueryInterface(isupports) );
|
||||
if (!txn) { return NS_ERROR_NULL_POINTER; }
|
||||
result = txn->Merge(aDidMerge, aTransaction);
|
||||
}
|
||||
}
|
||||
|
@ -148,22 +151,25 @@ NS_IMETHODIMP EditAggregateTxn::GetRedoString(nsString *aString)
|
|||
|
||||
NS_IMETHODIMP EditAggregateTxn::AppendChild(EditTxn *aTxn)
|
||||
{
|
||||
if ((nsnull!=mChildren) && (nsnull!=aTxn))
|
||||
if (mChildren && aTxn)
|
||||
{
|
||||
mChildren->AppendElement(aTxn);
|
||||
// aaahhhh! broken interfaces drive me crazy!!!
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
aTxn->QueryInterface(NS_GET_IID(nsISupports), getter_AddRefs(isupports));
|
||||
mChildren->AppendElement(isupports);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::GetCount(PRInt32 *aCount)
|
||||
NS_IMETHODIMP EditAggregateTxn::GetCount(PRUint32 *aCount)
|
||||
{
|
||||
if (!aCount) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
*aCount=0;
|
||||
if (mChildren) {
|
||||
*aCount = mChildren->Count();
|
||||
mChildren->Count(aCount);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -183,14 +189,16 @@ NS_IMETHODIMP EditAggregateTxn::GetTxnAt(PRInt32 aIndex, EditTxn **aTxn)
|
|||
}
|
||||
|
||||
// get the transaction at aIndex
|
||||
const PRInt32 txnCount = mChildren->Count();
|
||||
PRUint32 txnCount;
|
||||
mChildren->Count(&txnCount);
|
||||
if (0>aIndex || txnCount<=aIndex) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
*aTxn = (EditTxn *)(mChildren->ElementAt(aIndex));
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(mChildren->ElementAt(aIndex));
|
||||
// ugh, this is all wrong - what a mess we have with editor transaction interfaces
|
||||
isupports->QueryInterface(EditTxn::GetCID(), (void**)aTxn);
|
||||
if (!*aTxn)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
NS_ADDREF(*aTxn);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
#include "EditTxn.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupportsArray.h"
|
||||
|
||||
#define EDIT_AGGREGATE_TXN_CID \
|
||||
{/* 345921a0-ac49-11d2-86d8-000064657374 */ \
|
||||
0x345921a0, 0xac49, 0x11d2, \
|
||||
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
|
||||
|
||||
class nsVoidArray;
|
||||
|
||||
/**
|
||||
* base class for all document editing transactions that require aggregation.
|
||||
|
@ -68,7 +68,7 @@ public:
|
|||
/** get the number of nested txns.
|
||||
* This is the number of top-level txns, it does not do recursive decent.
|
||||
*/
|
||||
NS_IMETHOD GetCount(PRInt32 *aCount);
|
||||
NS_IMETHOD GetCount(PRUint32 *aCount);
|
||||
|
||||
/** get the txn at index aIndex.
|
||||
* returns NS_ERROR_UNEXPECTED if there is no txn at aIndex.
|
||||
|
@ -85,8 +85,7 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
//XXX: if this was an nsISupportsArray, it would handle refcounting for us
|
||||
nsVoidArray * mChildren;
|
||||
nsCOMPtr<nsISupportsArray> mChildren;
|
||||
nsCOMPtr<nsIAtom> mName;
|
||||
};
|
||||
|
||||
|
|
|
@ -356,25 +356,31 @@ nsEditor::Do(nsITransaction *aTxn)
|
|||
if (mPlaceHolderBatch && !mPlaceHolderTxn)
|
||||
{
|
||||
// it's pretty darn amazing how many different types of pointers
|
||||
// this transcation goes through here. I bet this is a record.
|
||||
// this transaction goes through here. I bet this is a record.
|
||||
|
||||
// We start off with an EditTxn since that's what the factory returns.
|
||||
EditTxn *editTxn;
|
||||
nsCOMPtr<nsIAbsorbingTransaction> plcTxn;
|
||||
result = TransactionFactory::GetNewTransaction(PlaceholderTxn::GetCID(), &editTxn);
|
||||
if (NS_FAILED(result)) { return result; }
|
||||
if (!editTxn) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
// Then we QI to an nsIAbsorbingTransaction to get at placeholder functionality
|
||||
nsCOMPtr<nsIAbsorbingTransaction> plcTxn;
|
||||
editTxn->QueryInterface(nsIAbsorbingTransaction::GetIID(), getter_AddRefs(plcTxn));
|
||||
// have to use line above instead of line below due to our broken
|
||||
// interface model for transactions.
|
||||
// plcTxn = do_QueryInterface(editTxn);
|
||||
// have to use line above instead of "plcTxn = do_QueryInterface(editTxn);"
|
||||
// due to our broken interface model for transactions.
|
||||
|
||||
// save off weak reference to placeholder txn
|
||||
mPlaceHolderTxn = getter_AddRefs( NS_GetWeakReference(plcTxn) );
|
||||
plcTxn->Init(mPresShellWeak, mPlaceHolderName, mTxnStartNode, mTxnStartOffset);
|
||||
// we will recurse, but will not hit this case in the nested call
|
||||
|
||||
// finally we QI to an nsITransaction since that's what Do() expects
|
||||
nsCOMPtr<nsITransaction> theTxn = do_QueryInterface(plcTxn);
|
||||
nsITransaction* txn = theTxn;
|
||||
// we want to escape from this routine with a positive refcount
|
||||
txn->AddRef();
|
||||
Do(txn);
|
||||
Do(txn); // we will recurse, but will not hit this case in the nested call
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
}
|
||||
|
||||
if (aTxn)
|
||||
|
@ -853,6 +859,8 @@ nsEditor::SetAttribute(nsIDOMElement *aElement, const nsString& aAttribute, cons
|
|||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -886,6 +894,8 @@ nsEditor::RemoveAttribute(nsIDOMElement *aElement, const nsString& aAttribute)
|
|||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -906,6 +916,8 @@ NS_IMETHODIMP nsEditor::CreateNode(const nsString& aTag,
|
|||
NS_ASSERTION((NS_SUCCEEDED(result)), "GetNewNode can't fail if txn::Do succeeded.");
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -932,6 +944,8 @@ NS_IMETHODIMP nsEditor::InsertNode(nsIDOMNode * aNode,
|
|||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (mActionListeners)
|
||||
{
|
||||
|
@ -976,6 +990,8 @@ nsEditor::SplitNode(nsIDOMNode * aNode,
|
|||
NS_ASSERTION((NS_SUCCEEDED(result)), "result must succeeded for GetNewNode");
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (mActionListeners)
|
||||
{
|
||||
|
@ -1020,6 +1036,10 @@ nsEditor::InsertNoneditableTextNode(nsIDOMNode* parent, PRInt32 offset,
|
|||
// Now get the pointer to the node we just created ...
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
res = txn->GetNewNode(getter_AddRefs(newNode));
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
nsCOMPtr<nsIDOMCharacterData> newTextNode;
|
||||
|
@ -1112,6 +1132,9 @@ nsEditor::JoinNodes(nsIDOMNode * aLeftNode,
|
|||
result = Do(txn);
|
||||
}
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (mActionListeners)
|
||||
{
|
||||
for (i = 0; i < mActionListeners->Count(); i++)
|
||||
|
@ -1147,6 +1170,9 @@ NS_IMETHODIMP nsEditor::DeleteNode(nsIDOMNode * aElement)
|
|||
result = Do(txn);
|
||||
}
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (mActionListeners)
|
||||
{
|
||||
for (i = 0; i < mActionListeners->Count(); i++)
|
||||
|
@ -1360,8 +1386,9 @@ nsEditor::EndComposition(void)
|
|||
// Note that this means IME won't work without an undo stack!
|
||||
if (mTxnMgr)
|
||||
{
|
||||
nsCOMPtr<nsITransaction> txn;
|
||||
result = mTxnMgr->PeekUndoStack(getter_AddRefs(txn));
|
||||
nsITransaction *txn;
|
||||
result = mTxnMgr->PeekUndoStack(&txn);
|
||||
// PeekUndoStack does not addref
|
||||
nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryInterface(txn);
|
||||
if (plcTxn)
|
||||
{
|
||||
|
@ -1589,6 +1616,9 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert)
|
|||
BeginUpdateViewBatch();
|
||||
result = Do(aggTxn);
|
||||
result = Do(txn);
|
||||
// The transaction system (if any) has taken ownwership of txns.
|
||||
// aggTxn released at end of routine.
|
||||
NS_IF_RELEASE(txn);
|
||||
EndUpdateViewBatch();
|
||||
}
|
||||
else if (NS_ERROR_EDITOR_NO_SELECTION==result)
|
||||
|
@ -1599,9 +1629,9 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert)
|
|||
{
|
||||
|
||||
// only execute the aggTxn if we actually populated it with at least one sub-txn
|
||||
PRInt32 count=0;
|
||||
PRUint32 count=0;
|
||||
aggTxn->GetCount(&count);
|
||||
if (0!=count)
|
||||
if (count)
|
||||
{
|
||||
result = Do(aggTxn);
|
||||
}
|
||||
|
@ -1609,6 +1639,8 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert)
|
|||
{
|
||||
result = NS_OK;
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txns
|
||||
NS_IF_RELEASE(aggTxn);
|
||||
|
||||
// create the text node
|
||||
if (NS_SUCCEEDED(result))
|
||||
|
@ -1645,6 +1677,8 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert)
|
|||
}
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txns
|
||||
NS_IF_RELEASE(aggTxn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1981,6 +2015,8 @@ NS_IMETHODIMP nsEditor::DoInitialInsert(const nsString & aStringToInsert)
|
|||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(insertTxn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(insertTxn);
|
||||
}
|
||||
else {
|
||||
result = NS_ERROR_UNEXPECTED;
|
||||
|
@ -1988,6 +2024,8 @@ NS_IMETHODIMP nsEditor::DoInitialInsert(const nsString & aStringToInsert)
|
|||
}
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -2003,6 +2041,8 @@ NS_IMETHODIMP nsEditor::DeleteText(nsIDOMCharacterData *aElement,
|
|||
result = Do(txn);
|
||||
// HACKForceRedraw();
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -3961,6 +4001,9 @@ nsEditor::DeleteSelectionImpl(ESelectionCollapseDirection aAction)
|
|||
result = Do(txn);
|
||||
}
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,9 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||
switch (info->action)
|
||||
{
|
||||
case kInsertText:
|
||||
return WillInsertText(aSelection,
|
||||
case kInsertTextIME:
|
||||
return WillInsertText(info->action,
|
||||
aSelection,
|
||||
aCancel,
|
||||
aHandled,
|
||||
info->inString,
|
||||
|
@ -148,7 +150,8 @@ nsHTMLEditRules::DidDoAction(nsIDOMSelection *aSelection,
|
|||
********************************************************/
|
||||
|
||||
nsresult
|
||||
nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
|
||||
nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
||||
nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled,
|
||||
const nsString *inString,
|
||||
|
@ -249,9 +252,11 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
|
|||
if (priorNode && IsBreak(priorNode) && HasMozAttr(priorNode)
|
||||
&& (blockParent == mEditor->GetBlockNodeParent(priorNode)))
|
||||
{
|
||||
needMozDiv = PR_TRUE;
|
||||
res = mEditor->DeleteNode(priorNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// but we only need to make a moz div if we weren't in a listitem
|
||||
if (!IsListItem(blockParent))
|
||||
needMozDiv = PR_TRUE;
|
||||
}
|
||||
|
||||
// if we are directly in a body or (non-moz) div, create a moz-div.
|
||||
|
@ -271,19 +276,22 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
|
|||
}
|
||||
|
||||
char nbspStr[2] = {nbsp, 0};
|
||||
|
||||
PRBool bCancel;
|
||||
nsString theString(*inString); // copy instring for now
|
||||
PRInt32 pos = theString.FindCharInSet(specialChars);
|
||||
if(0 == theString.Length()) {
|
||||
// special case for IME. We need this to remove the last
|
||||
// unconverted text.
|
||||
PRBool bCancel;
|
||||
nsString partialString;
|
||||
res = DoTextInsertion(aSelection, &bCancel, &partialString, typeInState);
|
||||
if(aAction == kInsertTextIME)
|
||||
{
|
||||
// special case for IME. We need this to :
|
||||
// a) handle null strings, which are meaningful for IME
|
||||
// b) prevent the string from being broken into substrings,
|
||||
// which can happen in non-IME processing below.
|
||||
// I should probably convert runs of spaces and tabs here as well
|
||||
res = DoTextInsertion(aSelection, &bCancel, &theString, typeInState);
|
||||
}
|
||||
else // aAction == kInsertText
|
||||
{
|
||||
while (theString.Length())
|
||||
{
|
||||
PRBool bCancel;
|
||||
nsString partialString;
|
||||
// if first char is special, then use just it
|
||||
if (pos == 0) pos = 1;
|
||||
|
@ -323,7 +331,7 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
|
|||
if (NS_FAILED(res)) return res;
|
||||
pos = theString.FindCharInSet(specialChars);
|
||||
}
|
||||
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -423,15 +431,8 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
|
|||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = mEditor->InsertBR(&brNode); // only inserts a br node
|
||||
res = InsertMozBR(); // inserts a br node with moz attr
|
||||
if (NS_FAILED(res)) return res;
|
||||
// give it special moz attr
|
||||
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(brNode);
|
||||
if (brElem)
|
||||
{
|
||||
res = mEditor->SetAttribute(brElem, "type", "_moz");
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
*aHandled = PR_TRUE;
|
||||
}
|
||||
else if (bIsMozDiv && AtStartOfBlock(node, offset, blockParent))
|
||||
|
@ -1671,6 +1672,17 @@ nsHTMLEditRules::IsMozDiv(nsIDOMNode *node)
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsMozBR: true if node an html br node with type = _moz
|
||||
//
|
||||
PRBool
|
||||
nsHTMLEditRules::IsMozBR(nsIDOMNode *node)
|
||||
{
|
||||
if (IsBreak(node) && HasMozAttr(node)) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// HasMozAttr: true if node has type attribute = _moz
|
||||
// (used to indicate the div's and br's we use in
|
||||
|
@ -1744,7 +1756,10 @@ nsHTMLEditRules::InBody(nsIDOMNode *node)
|
|||
// if the children are empty or non-editable.
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock)
|
||||
nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount,
|
||||
PRBool aListItemsNotEmpty)
|
||||
{
|
||||
if (!aNode || !outIsEmptyBlock) return NS_ERROR_NULL_POINTER;
|
||||
*outIsEmptyBlock = PR_TRUE;
|
||||
|
@ -1752,10 +1767,11 @@ nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock)
|
|||
// nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMNode> nodeToTest;
|
||||
if (nsEditor::IsBlockNode(aNode)) nodeToTest = do_QueryInterface(aNode);
|
||||
else nsCOMPtr<nsIDOMElement> block;
|
||||
// else nsCOMPtr<nsIDOMElement> block;
|
||||
// looks like I forgot to finish this. Wonder what I was going to do?
|
||||
|
||||
if (!nodeToTest) return NS_ERROR_NULL_POINTER;
|
||||
return IsEmptyNode(nodeToTest, outIsEmptyBlock);
|
||||
return IsEmptyNode(nodeToTest, outIsEmptyBlock, aMozBRDoesntCount, aListItemsNotEmpty);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1765,7 +1781,10 @@ nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock)
|
|||
// if the children are empty or non-editable.
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode)
|
||||
nsHTMLEditRules::IsEmptyNode( nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyNode,
|
||||
PRBool aMozBRDoesntCount,
|
||||
PRBool aListItemsNotEmpty)
|
||||
{
|
||||
if (!aNode || !outIsEmptyNode) return NS_ERROR_NULL_POINTER;
|
||||
*outIsEmptyNode = PR_TRUE;
|
||||
|
@ -1785,9 +1804,9 @@ nsHTMLEditRules::IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode)
|
|||
// then we dont call it empty (it's an <hr>, or <br>, etc).
|
||||
// Also, if it's an anchor then dont treat it as empty - even though
|
||||
// anchors are containers, named anchors are "empty" but we don't
|
||||
// want to treat them as such. Also, don't call ListItems empty:
|
||||
// empty list items still render and might be wanted.
|
||||
if (!mEditor->IsContainer(aNode) || IsAnchor(aNode) || IsListItem(aNode))
|
||||
// want to treat them as such. Also, don't call ListItems empty
|
||||
// if caller desires.
|
||||
if (!mEditor->IsContainer(aNode) || IsAnchor(aNode) || (aListItemsNotEmpty &&IsListItem(aNode)))
|
||||
{
|
||||
*outIsEmptyNode = PR_FALSE;
|
||||
return NS_OK;
|
||||
|
@ -1830,8 +1849,13 @@ nsHTMLEditRules::IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode)
|
|||
{
|
||||
// is it the node we are iterating over?
|
||||
if (node.get() == aNode) break;
|
||||
// is it a moz-BR and did the caller ask us not to consider those relevant?
|
||||
if (!(aMozBRDoesntCount && IsMozBR(node)))
|
||||
{
|
||||
// otherwise it ain't empty
|
||||
*outIsEmptyNode = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
res = iter->Next();
|
||||
|
@ -2634,6 +2658,25 @@ nsHTMLEditRules::InsertSpace(nsIDOMSelection *aSelection,
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// InsertMozBR: put a BR node with moz attribute at current insertion point
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::InsertMozBR()
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
nsresult res = mEditor->InsertBR(&brNode); // only inserts a br node
|
||||
if (NS_FAILED(res)) return res;
|
||||
// give it special moz attr
|
||||
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(brNode);
|
||||
if (brElem)
|
||||
{
|
||||
res = mEditor->SetAttribute(brElem, "type", "_moz");
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ReturnInHeader: do the right thing for returns pressed in headers
|
||||
//
|
||||
|
@ -2658,7 +2701,7 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
|
|||
|
||||
// if the new (righthand) header node is empty, delete it
|
||||
PRBool isEmpty;
|
||||
res = IsEmptyBlock(aHeader, &isEmpty);
|
||||
res = IsEmptyBlock(aHeader, &isEmpty, PR_TRUE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (isEmpty)
|
||||
{
|
||||
|
@ -2797,7 +2840,7 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
|
|||
|
||||
// if we are in an empty listitem, then we want to pop up out of the list
|
||||
PRBool isEmpty;
|
||||
res = IsEmptyBlock(aListItem, &isEmpty);
|
||||
res = IsEmptyBlock(aListItem, &isEmpty, PR_TRUE, PR_FALSE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (isEmpty)
|
||||
{
|
||||
|
@ -2832,6 +2875,8 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
|
|||
res = mEditor->SplitNodeDeep( aListItem, aNode, aOffset, &newOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = aSelection->Collapse(aListItem,0);
|
||||
// insert a moz-br
|
||||
InsertMozBR();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -3342,7 +3387,7 @@ nsHTMLEditRules::CleanUpSelection(nsIDOMSelection *aSelection)
|
|||
if (!node) return NS_ERROR_FAILURE;
|
||||
|
||||
PRBool bIsEmptyNode;
|
||||
res = IsEmptyNode(node, &bIsEmptyNode);
|
||||
res = IsEmptyNode(node, &bIsEmptyNode, PR_FALSE, PR_TRUE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsEmptyNode && !IsBody(node))
|
||||
{
|
||||
|
|
|
@ -47,7 +47,8 @@ protected:
|
|||
|
||||
|
||||
// nsHTMLEditRules implementation methods
|
||||
nsresult WillInsertText(nsIDOMSelection *aSelection,
|
||||
nsresult WillInsertText( PRInt32 aAction,
|
||||
nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled,
|
||||
const nsString *inString,
|
||||
|
@ -66,6 +67,7 @@ protected:
|
|||
|
||||
nsresult InsertTab(nsIDOMSelection *aSelection, nsString *outString);
|
||||
nsresult InsertSpace(nsIDOMSelection *aSelection, nsString *outString);
|
||||
nsresult InsertMozBR();
|
||||
|
||||
nsresult ReturnInHeader(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||
nsresult ReturnInParagraph(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
|
||||
|
@ -88,13 +90,20 @@ protected:
|
|||
static PRBool IsDiv(nsIDOMNode *aNode);
|
||||
static PRBool IsNormalDiv(nsIDOMNode *aNode);
|
||||
static PRBool IsMozDiv(nsIDOMNode *aNode);
|
||||
static PRBool IsMozBR(nsIDOMNode *aNode);
|
||||
static PRBool IsMailCite(nsIDOMNode *aNode);
|
||||
static PRBool HasMozAttr(nsIDOMNode *aNode);
|
||||
|
||||
static PRBool InBody(nsIDOMNode *aNode);
|
||||
|
||||
nsresult IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock);
|
||||
nsresult IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode);
|
||||
nsresult IsEmptyBlock(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount = PR_FALSE,
|
||||
PRBool aListItemsNotEmpty = PR_FALSE);
|
||||
nsresult IsEmptyNode(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount = PR_FALSE,
|
||||
PRBool aListItemsNotEmpty = PR_FALSE);
|
||||
PRBool IsFirstNode(nsIDOMNode *aNode);
|
||||
PRBool IsLastNode(nsIDOMNode *aNode);
|
||||
PRBool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
|
||||
|
|
|
@ -1260,6 +1260,8 @@ NS_IMETHODIMP nsHTMLEditor::InsertText(const nsString& aStringToInsert)
|
|||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
nsAutoString resultString;
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertText);
|
||||
// set a different action flag if we are an IME event
|
||||
if (mInIMEMode) ruleInfo.action = nsTextEditRules::kInsertTextIME;
|
||||
ruleInfo.inString = &aStringToInsert;
|
||||
ruleInfo.outString = &resultString;
|
||||
ruleInfo.typeInState = *mTypeInState;
|
||||
|
@ -2881,6 +2883,8 @@ nsHTMLEditor::AddStyleSheet(nsICSSStyleSheet* aSheet)
|
|||
mLastStyleSheet = do_QueryInterface(aSheet); // save it so we can remove before applying the next one
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txns
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -2900,6 +2904,8 @@ nsHTMLEditor::RemoveStyleSheet(nsICSSStyleSheet* aSheet)
|
|||
mLastStyleSheet = nsnull; // forget it
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txns
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -25,36 +25,29 @@ EditAggregateTxn::EditAggregateTxn()
|
|||
: EditTxn()
|
||||
{
|
||||
// base class does this: NS_INIT_REFCNT();
|
||||
mChildren = new nsVoidArray();
|
||||
nsresult res = NS_NewISupportsArray(getter_AddRefs(mChildren));
|
||||
NS_POSTCONDITION(NS_SUCCEEDED(res), "EditAggregateTxn failed in constructor");
|
||||
SetTransactionDescriptionID( kTransactionID );
|
||||
/* log description initialized in parent constructor */
|
||||
}
|
||||
|
||||
EditAggregateTxn::~EditAggregateTxn()
|
||||
{
|
||||
if (nsnull!=mChildren)
|
||||
{
|
||||
PRInt32 i;
|
||||
PRInt32 count = mChildren->Count();
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
|
||||
NS_IF_RELEASE(txn);
|
||||
}
|
||||
delete mChildren;
|
||||
}
|
||||
// nsISupportsArray cleans up array for us at destruct time
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::Do(void)
|
||||
{
|
||||
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
|
||||
if (nsnull!=mChildren)
|
||||
if (mChildren)
|
||||
{
|
||||
PRInt32 i;
|
||||
PRInt32 count = mChildren->Count();
|
||||
PRUint32 count;
|
||||
mChildren->Count(&count);
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsITransaction> txn ( do_QueryInterface(isupports) );
|
||||
if (!txn) { return NS_ERROR_NULL_POINTER; }
|
||||
result = txn->Do();
|
||||
if (NS_FAILED(result))
|
||||
|
@ -67,14 +60,17 @@ NS_IMETHODIMP EditAggregateTxn::Do(void)
|
|||
NS_IMETHODIMP EditAggregateTxn::Undo(void)
|
||||
{
|
||||
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
|
||||
if (nsnull!=mChildren)
|
||||
if (mChildren)
|
||||
{
|
||||
PRInt32 i;
|
||||
PRInt32 count = mChildren->Count();
|
||||
PRUint32 count;
|
||||
mChildren->Count(&count);
|
||||
// undo goes through children backwards
|
||||
for (i=count-1; i>=0; i--)
|
||||
{
|
||||
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsITransaction> txn ( do_QueryInterface(isupports) );
|
||||
if (!txn) { return NS_ERROR_NULL_POINTER; }
|
||||
result = txn->Undo();
|
||||
if (NS_FAILED(result))
|
||||
break;
|
||||
|
@ -86,13 +82,16 @@ NS_IMETHODIMP EditAggregateTxn::Undo(void)
|
|||
NS_IMETHODIMP EditAggregateTxn::Redo(void)
|
||||
{
|
||||
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
|
||||
if (nsnull!=mChildren)
|
||||
if (mChildren)
|
||||
{
|
||||
PRInt32 i;
|
||||
PRInt32 count = mChildren->Count();
|
||||
PRUint32 count;
|
||||
mChildren->Count(&count);
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsITransaction> txn ( do_QueryInterface(isupports) );
|
||||
if (!txn) { return NS_ERROR_NULL_POINTER; }
|
||||
result = txn->Redo();
|
||||
if (NS_FAILED(result))
|
||||
break;
|
||||
|
@ -113,13 +112,17 @@ NS_IMETHODIMP EditAggregateTxn::Merge(PRBool *aDidMerge, nsITransaction *aTransa
|
|||
nsresult result=NS_OK; // it's legal (but not very useful) to have an empty child list
|
||||
if (nsnull!=aDidMerge)
|
||||
*aDidMerge=PR_FALSE;
|
||||
if (nsnull!=mChildren)
|
||||
if (mChildren)
|
||||
{
|
||||
PRInt32 count = mChildren->Count();
|
||||
PRInt32 i;
|
||||
PRUint32 count;
|
||||
mChildren->Count(&count);
|
||||
NS_ASSERTION(count>0, "bad count");
|
||||
if (0<count)
|
||||
{
|
||||
EditTxn *txn = (EditTxn*)(mChildren->ElementAt(count-1));
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(mChildren->ElementAt(i));
|
||||
nsCOMPtr<nsITransaction> txn ( do_QueryInterface(isupports) );
|
||||
if (!txn) { return NS_ERROR_NULL_POINTER; }
|
||||
result = txn->Merge(aDidMerge, aTransaction);
|
||||
}
|
||||
}
|
||||
|
@ -148,22 +151,25 @@ NS_IMETHODIMP EditAggregateTxn::GetRedoString(nsString *aString)
|
|||
|
||||
NS_IMETHODIMP EditAggregateTxn::AppendChild(EditTxn *aTxn)
|
||||
{
|
||||
if ((nsnull!=mChildren) && (nsnull!=aTxn))
|
||||
if (mChildren && aTxn)
|
||||
{
|
||||
mChildren->AppendElement(aTxn);
|
||||
// aaahhhh! broken interfaces drive me crazy!!!
|
||||
nsCOMPtr<nsISupports> isupports;
|
||||
aTxn->QueryInterface(NS_GET_IID(nsISupports), getter_AddRefs(isupports));
|
||||
mChildren->AppendElement(isupports);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP EditAggregateTxn::GetCount(PRInt32 *aCount)
|
||||
NS_IMETHODIMP EditAggregateTxn::GetCount(PRUint32 *aCount)
|
||||
{
|
||||
if (!aCount) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
*aCount=0;
|
||||
if (mChildren) {
|
||||
*aCount = mChildren->Count();
|
||||
mChildren->Count(aCount);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -183,14 +189,16 @@ NS_IMETHODIMP EditAggregateTxn::GetTxnAt(PRInt32 aIndex, EditTxn **aTxn)
|
|||
}
|
||||
|
||||
// get the transaction at aIndex
|
||||
const PRInt32 txnCount = mChildren->Count();
|
||||
PRUint32 txnCount;
|
||||
mChildren->Count(&txnCount);
|
||||
if (0>aIndex || txnCount<=aIndex) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
*aTxn = (EditTxn *)(mChildren->ElementAt(aIndex));
|
||||
nsCOMPtr<nsISupports> isupports = (dont_AddRef)(mChildren->ElementAt(aIndex));
|
||||
// ugh, this is all wrong - what a mess we have with editor transaction interfaces
|
||||
isupports->QueryInterface(EditTxn::GetCID(), (void**)aTxn);
|
||||
if (!*aTxn)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
NS_ADDREF(*aTxn);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,13 +22,13 @@
|
|||
#include "EditTxn.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupportsArray.h"
|
||||
|
||||
#define EDIT_AGGREGATE_TXN_CID \
|
||||
{/* 345921a0-ac49-11d2-86d8-000064657374 */ \
|
||||
0x345921a0, 0xac49, 0x11d2, \
|
||||
{0x86, 0xd8, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74} }
|
||||
|
||||
class nsVoidArray;
|
||||
|
||||
/**
|
||||
* base class for all document editing transactions that require aggregation.
|
||||
|
@ -68,7 +68,7 @@ public:
|
|||
/** get the number of nested txns.
|
||||
* This is the number of top-level txns, it does not do recursive decent.
|
||||
*/
|
||||
NS_IMETHOD GetCount(PRInt32 *aCount);
|
||||
NS_IMETHOD GetCount(PRUint32 *aCount);
|
||||
|
||||
/** get the txn at index aIndex.
|
||||
* returns NS_ERROR_UNEXPECTED if there is no txn at aIndex.
|
||||
|
@ -85,8 +85,7 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
//XXX: if this was an nsISupportsArray, it would handle refcounting for us
|
||||
nsVoidArray * mChildren;
|
||||
nsCOMPtr<nsISupportsArray> mChildren;
|
||||
nsCOMPtr<nsIAtom> mName;
|
||||
};
|
||||
|
||||
|
|
|
@ -356,25 +356,31 @@ nsEditor::Do(nsITransaction *aTxn)
|
|||
if (mPlaceHolderBatch && !mPlaceHolderTxn)
|
||||
{
|
||||
// it's pretty darn amazing how many different types of pointers
|
||||
// this transcation goes through here. I bet this is a record.
|
||||
// this transaction goes through here. I bet this is a record.
|
||||
|
||||
// We start off with an EditTxn since that's what the factory returns.
|
||||
EditTxn *editTxn;
|
||||
nsCOMPtr<nsIAbsorbingTransaction> plcTxn;
|
||||
result = TransactionFactory::GetNewTransaction(PlaceholderTxn::GetCID(), &editTxn);
|
||||
if (NS_FAILED(result)) { return result; }
|
||||
if (!editTxn) { return NS_ERROR_NULL_POINTER; }
|
||||
|
||||
// Then we QI to an nsIAbsorbingTransaction to get at placeholder functionality
|
||||
nsCOMPtr<nsIAbsorbingTransaction> plcTxn;
|
||||
editTxn->QueryInterface(nsIAbsorbingTransaction::GetIID(), getter_AddRefs(plcTxn));
|
||||
// have to use line above instead of line below due to our broken
|
||||
// interface model for transactions.
|
||||
// plcTxn = do_QueryInterface(editTxn);
|
||||
// have to use line above instead of "plcTxn = do_QueryInterface(editTxn);"
|
||||
// due to our broken interface model for transactions.
|
||||
|
||||
// save off weak reference to placeholder txn
|
||||
mPlaceHolderTxn = getter_AddRefs( NS_GetWeakReference(plcTxn) );
|
||||
plcTxn->Init(mPresShellWeak, mPlaceHolderName, mTxnStartNode, mTxnStartOffset);
|
||||
// we will recurse, but will not hit this case in the nested call
|
||||
|
||||
// finally we QI to an nsITransaction since that's what Do() expects
|
||||
nsCOMPtr<nsITransaction> theTxn = do_QueryInterface(plcTxn);
|
||||
nsITransaction* txn = theTxn;
|
||||
// we want to escape from this routine with a positive refcount
|
||||
txn->AddRef();
|
||||
Do(txn);
|
||||
Do(txn); // we will recurse, but will not hit this case in the nested call
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
}
|
||||
|
||||
if (aTxn)
|
||||
|
@ -853,6 +859,8 @@ nsEditor::SetAttribute(nsIDOMElement *aElement, const nsString& aAttribute, cons
|
|||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -886,6 +894,8 @@ nsEditor::RemoveAttribute(nsIDOMElement *aElement, const nsString& aAttribute)
|
|||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -906,6 +916,8 @@ NS_IMETHODIMP nsEditor::CreateNode(const nsString& aTag,
|
|||
NS_ASSERTION((NS_SUCCEEDED(result)), "GetNewNode can't fail if txn::Do succeeded.");
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -932,6 +944,8 @@ NS_IMETHODIMP nsEditor::InsertNode(nsIDOMNode * aNode,
|
|||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(txn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (mActionListeners)
|
||||
{
|
||||
|
@ -976,6 +990,8 @@ nsEditor::SplitNode(nsIDOMNode * aNode,
|
|||
NS_ASSERTION((NS_SUCCEEDED(result)), "result must succeeded for GetNewNode");
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (mActionListeners)
|
||||
{
|
||||
|
@ -1020,6 +1036,10 @@ nsEditor::InsertNoneditableTextNode(nsIDOMNode* parent, PRInt32 offset,
|
|||
// Now get the pointer to the node we just created ...
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
res = txn->GetNewNode(getter_AddRefs(newNode));
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (NS_FAILED(res))
|
||||
return res;
|
||||
nsCOMPtr<nsIDOMCharacterData> newTextNode;
|
||||
|
@ -1112,6 +1132,9 @@ nsEditor::JoinNodes(nsIDOMNode * aLeftNode,
|
|||
result = Do(txn);
|
||||
}
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (mActionListeners)
|
||||
{
|
||||
for (i = 0; i < mActionListeners->Count(); i++)
|
||||
|
@ -1147,6 +1170,9 @@ NS_IMETHODIMP nsEditor::DeleteNode(nsIDOMNode * aElement)
|
|||
result = Do(txn);
|
||||
}
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
if (mActionListeners)
|
||||
{
|
||||
for (i = 0; i < mActionListeners->Count(); i++)
|
||||
|
@ -1360,8 +1386,9 @@ nsEditor::EndComposition(void)
|
|||
// Note that this means IME won't work without an undo stack!
|
||||
if (mTxnMgr)
|
||||
{
|
||||
nsCOMPtr<nsITransaction> txn;
|
||||
result = mTxnMgr->PeekUndoStack(getter_AddRefs(txn));
|
||||
nsITransaction *txn;
|
||||
result = mTxnMgr->PeekUndoStack(&txn);
|
||||
// PeekUndoStack does not addref
|
||||
nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryInterface(txn);
|
||||
if (plcTxn)
|
||||
{
|
||||
|
@ -1589,6 +1616,9 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert)
|
|||
BeginUpdateViewBatch();
|
||||
result = Do(aggTxn);
|
||||
result = Do(txn);
|
||||
// The transaction system (if any) has taken ownwership of txns.
|
||||
// aggTxn released at end of routine.
|
||||
NS_IF_RELEASE(txn);
|
||||
EndUpdateViewBatch();
|
||||
}
|
||||
else if (NS_ERROR_EDITOR_NO_SELECTION==result)
|
||||
|
@ -1599,9 +1629,9 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert)
|
|||
{
|
||||
|
||||
// only execute the aggTxn if we actually populated it with at least one sub-txn
|
||||
PRInt32 count=0;
|
||||
PRUint32 count=0;
|
||||
aggTxn->GetCount(&count);
|
||||
if (0!=count)
|
||||
if (count)
|
||||
{
|
||||
result = Do(aggTxn);
|
||||
}
|
||||
|
@ -1609,6 +1639,8 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert)
|
|||
{
|
||||
result = NS_OK;
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txns
|
||||
NS_IF_RELEASE(aggTxn);
|
||||
|
||||
// create the text node
|
||||
if (NS_SUCCEEDED(result))
|
||||
|
@ -1645,6 +1677,8 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsString& aStringToInsert)
|
|||
}
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txns
|
||||
NS_IF_RELEASE(aggTxn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1981,6 +2015,8 @@ NS_IMETHODIMP nsEditor::DoInitialInsert(const nsString & aStringToInsert)
|
|||
if (NS_SUCCEEDED(result)) {
|
||||
result = Do(insertTxn);
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(insertTxn);
|
||||
}
|
||||
else {
|
||||
result = NS_ERROR_UNEXPECTED;
|
||||
|
@ -1988,6 +2024,8 @@ NS_IMETHODIMP nsEditor::DoInitialInsert(const nsString & aStringToInsert)
|
|||
}
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -2003,6 +2041,8 @@ NS_IMETHODIMP nsEditor::DeleteText(nsIDOMCharacterData *aElement,
|
|||
result = Do(txn);
|
||||
// HACKForceRedraw();
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -3961,6 +4001,9 @@ nsEditor::DeleteSelectionImpl(ESelectionCollapseDirection aAction)
|
|||
result = Do(txn);
|
||||
}
|
||||
|
||||
// The transaction system (if any) has taken ownwership of txn
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,9 @@ nsHTMLEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
|||
switch (info->action)
|
||||
{
|
||||
case kInsertText:
|
||||
return WillInsertText(aSelection,
|
||||
case kInsertTextIME:
|
||||
return WillInsertText(info->action,
|
||||
aSelection,
|
||||
aCancel,
|
||||
aHandled,
|
||||
info->inString,
|
||||
|
@ -148,7 +150,8 @@ nsHTMLEditRules::DidDoAction(nsIDOMSelection *aSelection,
|
|||
********************************************************/
|
||||
|
||||
nsresult
|
||||
nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
|
||||
nsHTMLEditRules::WillInsertText(PRInt32 aAction,
|
||||
nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled,
|
||||
const nsString *inString,
|
||||
|
@ -249,9 +252,11 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
|
|||
if (priorNode && IsBreak(priorNode) && HasMozAttr(priorNode)
|
||||
&& (blockParent == mEditor->GetBlockNodeParent(priorNode)))
|
||||
{
|
||||
needMozDiv = PR_TRUE;
|
||||
res = mEditor->DeleteNode(priorNode);
|
||||
if (NS_FAILED(res)) return res;
|
||||
// but we only need to make a moz div if we weren't in a listitem
|
||||
if (!IsListItem(blockParent))
|
||||
needMozDiv = PR_TRUE;
|
||||
}
|
||||
|
||||
// if we are directly in a body or (non-moz) div, create a moz-div.
|
||||
|
@ -271,19 +276,22 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
|
|||
}
|
||||
|
||||
char nbspStr[2] = {nbsp, 0};
|
||||
|
||||
PRBool bCancel;
|
||||
nsString theString(*inString); // copy instring for now
|
||||
PRInt32 pos = theString.FindCharInSet(specialChars);
|
||||
if(0 == theString.Length()) {
|
||||
// special case for IME. We need this to remove the last
|
||||
// unconverted text.
|
||||
PRBool bCancel;
|
||||
nsString partialString;
|
||||
res = DoTextInsertion(aSelection, &bCancel, &partialString, typeInState);
|
||||
if(aAction == kInsertTextIME)
|
||||
{
|
||||
// special case for IME. We need this to :
|
||||
// a) handle null strings, which are meaningful for IME
|
||||
// b) prevent the string from being broken into substrings,
|
||||
// which can happen in non-IME processing below.
|
||||
// I should probably convert runs of spaces and tabs here as well
|
||||
res = DoTextInsertion(aSelection, &bCancel, &theString, typeInState);
|
||||
}
|
||||
else // aAction == kInsertText
|
||||
{
|
||||
while (theString.Length())
|
||||
{
|
||||
PRBool bCancel;
|
||||
nsString partialString;
|
||||
// if first char is special, then use just it
|
||||
if (pos == 0) pos = 1;
|
||||
|
@ -323,7 +331,7 @@ nsHTMLEditRules::WillInsertText(nsIDOMSelection *aSelection,
|
|||
if (NS_FAILED(res)) return res;
|
||||
pos = theString.FindCharInSet(specialChars);
|
||||
}
|
||||
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -423,15 +431,8 @@ nsHTMLEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, P
|
|||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = mEditor->InsertBR(&brNode); // only inserts a br node
|
||||
res = InsertMozBR(); // inserts a br node with moz attr
|
||||
if (NS_FAILED(res)) return res;
|
||||
// give it special moz attr
|
||||
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(brNode);
|
||||
if (brElem)
|
||||
{
|
||||
res = mEditor->SetAttribute(brElem, "type", "_moz");
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
*aHandled = PR_TRUE;
|
||||
}
|
||||
else if (bIsMozDiv && AtStartOfBlock(node, offset, blockParent))
|
||||
|
@ -1671,6 +1672,17 @@ nsHTMLEditRules::IsMozDiv(nsIDOMNode *node)
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IsMozBR: true if node an html br node with type = _moz
|
||||
//
|
||||
PRBool
|
||||
nsHTMLEditRules::IsMozBR(nsIDOMNode *node)
|
||||
{
|
||||
if (IsBreak(node) && HasMozAttr(node)) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// HasMozAttr: true if node has type attribute = _moz
|
||||
// (used to indicate the div's and br's we use in
|
||||
|
@ -1744,7 +1756,10 @@ nsHTMLEditRules::InBody(nsIDOMNode *node)
|
|||
// if the children are empty or non-editable.
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock)
|
||||
nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount,
|
||||
PRBool aListItemsNotEmpty)
|
||||
{
|
||||
if (!aNode || !outIsEmptyBlock) return NS_ERROR_NULL_POINTER;
|
||||
*outIsEmptyBlock = PR_TRUE;
|
||||
|
@ -1752,10 +1767,11 @@ nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock)
|
|||
// nsresult res = NS_OK;
|
||||
nsCOMPtr<nsIDOMNode> nodeToTest;
|
||||
if (nsEditor::IsBlockNode(aNode)) nodeToTest = do_QueryInterface(aNode);
|
||||
else nsCOMPtr<nsIDOMElement> block;
|
||||
// else nsCOMPtr<nsIDOMElement> block;
|
||||
// looks like I forgot to finish this. Wonder what I was going to do?
|
||||
|
||||
if (!nodeToTest) return NS_ERROR_NULL_POINTER;
|
||||
return IsEmptyNode(nodeToTest, outIsEmptyBlock);
|
||||
return IsEmptyNode(nodeToTest, outIsEmptyBlock, aMozBRDoesntCount, aListItemsNotEmpty);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1765,7 +1781,10 @@ nsHTMLEditRules::IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock)
|
|||
// if the children are empty or non-editable.
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode)
|
||||
nsHTMLEditRules::IsEmptyNode( nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyNode,
|
||||
PRBool aMozBRDoesntCount,
|
||||
PRBool aListItemsNotEmpty)
|
||||
{
|
||||
if (!aNode || !outIsEmptyNode) return NS_ERROR_NULL_POINTER;
|
||||
*outIsEmptyNode = PR_TRUE;
|
||||
|
@ -1785,9 +1804,9 @@ nsHTMLEditRules::IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode)
|
|||
// then we dont call it empty (it's an <hr>, or <br>, etc).
|
||||
// Also, if it's an anchor then dont treat it as empty - even though
|
||||
// anchors are containers, named anchors are "empty" but we don't
|
||||
// want to treat them as such. Also, don't call ListItems empty:
|
||||
// empty list items still render and might be wanted.
|
||||
if (!mEditor->IsContainer(aNode) || IsAnchor(aNode) || IsListItem(aNode))
|
||||
// want to treat them as such. Also, don't call ListItems empty
|
||||
// if caller desires.
|
||||
if (!mEditor->IsContainer(aNode) || IsAnchor(aNode) || (aListItemsNotEmpty &&IsListItem(aNode)))
|
||||
{
|
||||
*outIsEmptyNode = PR_FALSE;
|
||||
return NS_OK;
|
||||
|
@ -1830,8 +1849,13 @@ nsHTMLEditRules::IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode)
|
|||
{
|
||||
// is it the node we are iterating over?
|
||||
if (node.get() == aNode) break;
|
||||
// is it a moz-BR and did the caller ask us not to consider those relevant?
|
||||
if (!(aMozBRDoesntCount && IsMozBR(node)))
|
||||
{
|
||||
// otherwise it ain't empty
|
||||
*outIsEmptyNode = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
res = iter->Next();
|
||||
|
@ -2634,6 +2658,25 @@ nsHTMLEditRules::InsertSpace(nsIDOMSelection *aSelection,
|
|||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// InsertMozBR: put a BR node with moz attribute at current insertion point
|
||||
//
|
||||
nsresult
|
||||
nsHTMLEditRules::InsertMozBR()
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
nsresult res = mEditor->InsertBR(&brNode); // only inserts a br node
|
||||
if (NS_FAILED(res)) return res;
|
||||
// give it special moz attr
|
||||
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(brNode);
|
||||
if (brElem)
|
||||
{
|
||||
res = mEditor->SetAttribute(brElem, "type", "_moz");
|
||||
if (NS_FAILED(res)) return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ReturnInHeader: do the right thing for returns pressed in headers
|
||||
//
|
||||
|
@ -2658,7 +2701,7 @@ nsHTMLEditRules::ReturnInHeader(nsIDOMSelection *aSelection,
|
|||
|
||||
// if the new (righthand) header node is empty, delete it
|
||||
PRBool isEmpty;
|
||||
res = IsEmptyBlock(aHeader, &isEmpty);
|
||||
res = IsEmptyBlock(aHeader, &isEmpty, PR_TRUE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (isEmpty)
|
||||
{
|
||||
|
@ -2797,7 +2840,7 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
|
|||
|
||||
// if we are in an empty listitem, then we want to pop up out of the list
|
||||
PRBool isEmpty;
|
||||
res = IsEmptyBlock(aListItem, &isEmpty);
|
||||
res = IsEmptyBlock(aListItem, &isEmpty, PR_TRUE, PR_FALSE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (isEmpty)
|
||||
{
|
||||
|
@ -2832,6 +2875,8 @@ nsHTMLEditRules::ReturnInListItem(nsIDOMSelection *aSelection,
|
|||
res = mEditor->SplitNodeDeep( aListItem, aNode, aOffset, &newOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
res = aSelection->Collapse(aListItem,0);
|
||||
// insert a moz-br
|
||||
InsertMozBR();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -3342,7 +3387,7 @@ nsHTMLEditRules::CleanUpSelection(nsIDOMSelection *aSelection)
|
|||
if (!node) return NS_ERROR_FAILURE;
|
||||
|
||||
PRBool bIsEmptyNode;
|
||||
res = IsEmptyNode(node, &bIsEmptyNode);
|
||||
res = IsEmptyNode(node, &bIsEmptyNode, PR_FALSE, PR_TRUE);
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (bIsEmptyNode && !IsBody(node))
|
||||
{
|
||||
|
|
|
@ -47,7 +47,8 @@ protected:
|
|||
|
||||
|
||||
// nsHTMLEditRules implementation methods
|
||||
nsresult WillInsertText(nsIDOMSelection *aSelection,
|
||||
nsresult WillInsertText( PRInt32 aAction,
|
||||
nsIDOMSelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled,
|
||||
const nsString *inString,
|
||||
|
@ -66,6 +67,7 @@ protected:
|
|||
|
||||
nsresult InsertTab(nsIDOMSelection *aSelection, nsString *outString);
|
||||
nsresult InsertSpace(nsIDOMSelection *aSelection, nsString *outString);
|
||||
nsresult InsertMozBR();
|
||||
|
||||
nsresult ReturnInHeader(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset);
|
||||
nsresult ReturnInParagraph(nsIDOMSelection *aSelection, nsIDOMNode *aHeader, nsIDOMNode *aTextNode, PRInt32 aOffset, PRBool *aCancel, PRBool *aHandled);
|
||||
|
@ -88,13 +90,20 @@ protected:
|
|||
static PRBool IsDiv(nsIDOMNode *aNode);
|
||||
static PRBool IsNormalDiv(nsIDOMNode *aNode);
|
||||
static PRBool IsMozDiv(nsIDOMNode *aNode);
|
||||
static PRBool IsMozBR(nsIDOMNode *aNode);
|
||||
static PRBool IsMailCite(nsIDOMNode *aNode);
|
||||
static PRBool HasMozAttr(nsIDOMNode *aNode);
|
||||
|
||||
static PRBool InBody(nsIDOMNode *aNode);
|
||||
|
||||
nsresult IsEmptyBlock(nsIDOMNode *aNode, PRBool *outIsEmptyBlock);
|
||||
nsresult IsEmptyNode(nsIDOMNode *aNode, PRBool *outIsEmptyNode);
|
||||
nsresult IsEmptyBlock(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount = PR_FALSE,
|
||||
PRBool aListItemsNotEmpty = PR_FALSE);
|
||||
nsresult IsEmptyNode(nsIDOMNode *aNode,
|
||||
PRBool *outIsEmptyBlock,
|
||||
PRBool aMozBRDoesntCount = PR_FALSE,
|
||||
PRBool aListItemsNotEmpty = PR_FALSE);
|
||||
PRBool IsFirstNode(nsIDOMNode *aNode);
|
||||
PRBool IsLastNode(nsIDOMNode *aNode);
|
||||
PRBool AtStartOfBlock(nsIDOMNode *aNode, PRInt32 aOffset, nsIDOMNode *aBlock);
|
||||
|
|
|
@ -1260,6 +1260,8 @@ NS_IMETHODIMP nsHTMLEditor::InsertText(const nsString& aStringToInsert)
|
|||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
nsAutoString resultString;
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertText);
|
||||
// set a different action flag if we are an IME event
|
||||
if (mInIMEMode) ruleInfo.action = nsTextEditRules::kInsertTextIME;
|
||||
ruleInfo.inString = &aStringToInsert;
|
||||
ruleInfo.outString = &resultString;
|
||||
ruleInfo.typeInState = *mTypeInState;
|
||||
|
@ -2881,6 +2883,8 @@ nsHTMLEditor::AddStyleSheet(nsICSSStyleSheet* aSheet)
|
|||
mLastStyleSheet = do_QueryInterface(aSheet); // save it so we can remove before applying the next one
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txns
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -2900,6 +2904,8 @@ nsHTMLEditor::RemoveStyleSheet(nsICSSStyleSheet* aSheet)
|
|||
mLastStyleSheet = nsnull; // forget it
|
||||
}
|
||||
}
|
||||
// The transaction system (if any) has taken ownwership of txns
|
||||
NS_IF_RELEASE(txn);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче