bug 66290: embedding work: refactor editor to allow smaller plaintext only library. Embedding clients may be interested inthis library if they want to embed a browser but not composer/mail-compose. Reduces library footprint for plaintext-only library by over 50% on all three platforms. r=fm; sr=kin
git-svn-id: svn://10.0.0.236/trunk@85666 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -59,6 +59,7 @@
|
||||
#include "nsIKBStateControl.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIScrollbar.h"
|
||||
#include "nsIPlaintextEditor.h"
|
||||
|
||||
#include "nsIFrame.h" // Needed by IME code
|
||||
|
||||
@@ -93,7 +94,7 @@
|
||||
#include "JoinElementTxn.h"
|
||||
#include "nsStyleSheetTxns.h"
|
||||
#include "IMETextTxn.h"
|
||||
#include "nsIHTMLEditor.h"
|
||||
|
||||
// included for nsEditor::CreateHTMLContent
|
||||
#include "nsIElementFactory.h"
|
||||
#include "nsINodeInfo.h"
|
||||
@@ -148,738 +149,6 @@ const PRUnichar nbsp = 160;
|
||||
PRInt32 nsEditor::gInstanceCount = 0;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* class for recording selection info. stores selection as collection of
|
||||
* { {startnode, startoffset} , {endnode, endoffset} } tuples. Cant store
|
||||
* ranges since dom gravity will possibly change the ranges.
|
||||
*/
|
||||
nsSelectionState::nsSelectionState() : mArray(){}
|
||||
|
||||
nsSelectionState::~nsSelectionState()
|
||||
{
|
||||
MakeEmpty();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSelectionState::SaveSelection(nsISelection *aSel)
|
||||
{
|
||||
if (!aSel) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 i,rangeCount, arrayCount = mArray.Count();
|
||||
nsRangeStore *item;
|
||||
aSel->GetRangeCount(&rangeCount);
|
||||
|
||||
// if we need more items in the array, new them
|
||||
if (arrayCount<rangeCount)
|
||||
{
|
||||
PRInt32 count = rangeCount-arrayCount;
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = new nsRangeStore;
|
||||
mArray.AppendElement(item);
|
||||
}
|
||||
}
|
||||
|
||||
// else if we have too many, delete them
|
||||
else if (rangeCount>arrayCount)
|
||||
{
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(rangeCount)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(rangeCount);
|
||||
}
|
||||
}
|
||||
|
||||
// now store the selection ranges
|
||||
for (i=0; i<rangeCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
res = aSel->GetRangeAt(i, getter_AddRefs(range));
|
||||
item->StoreRange(range);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSelectionState::RestoreSelection(nsISelection *aSel)
|
||||
{
|
||||
if (!aSel) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 i, arrayCount = mArray.Count();
|
||||
nsRangeStore *item;
|
||||
|
||||
// clear out selection
|
||||
aSel->RemoveAllRanges();
|
||||
|
||||
// set the selection ranges anew
|
||||
for (i=0; i<arrayCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_UNEXPECTED;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
item->GetRange(address_of(range));
|
||||
if (!range) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
res = aSel->AddRange(range);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsCollapsed()
|
||||
{
|
||||
if (1 != mArray.Count()) return PR_FALSE;
|
||||
nsRangeStore *item;
|
||||
item = (nsRangeStore*)mArray.ElementAt(0);
|
||||
if (!item) return PR_FALSE;
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
item->GetRange(address_of(range));
|
||||
if (!range) return PR_FALSE;
|
||||
PRBool bIsCollapsed;
|
||||
range->GetCollapsed(&bIsCollapsed);
|
||||
return bIsCollapsed;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsEqual(nsSelectionState *aSelState)
|
||||
{
|
||||
if (!aSelState) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, myCount = mArray.Count(), itsCount = aSelState->mArray.Count();
|
||||
if (myCount != itsCount) return PR_FALSE;
|
||||
if (myCount < 1) return PR_FALSE;
|
||||
|
||||
nsRangeStore *myItem, *itsItem;
|
||||
|
||||
for (i=0; i<myCount; i++)
|
||||
{
|
||||
myItem = (nsRangeStore*)mArray.ElementAt(0);
|
||||
itsItem = (nsRangeStore*)(aSelState->mArray.ElementAt(0));
|
||||
if (!myItem || !itsItem) return PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMRange> myRange, itsRange;
|
||||
myItem->GetRange(address_of(myRange));
|
||||
itsItem->GetRange(address_of(itsRange));
|
||||
if (!myRange || !itsRange) return PR_FALSE;
|
||||
|
||||
PRInt32 compResult;
|
||||
myRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, itsRange, &compResult);
|
||||
if (compResult) return PR_FALSE;
|
||||
myRange->CompareBoundaryPoints(nsIDOMRange::END_TO_END, itsRange, &compResult);
|
||||
if (compResult) return PR_FALSE;
|
||||
}
|
||||
// if we got here, they are equal
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsSelectionState::MakeEmpty()
|
||||
{
|
||||
// free any items in the array
|
||||
nsRangeStore *item;
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSelectionState::IsEmpty()
|
||||
{
|
||||
return (mArray.Count() == 0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* nsRangeUpdater: class for updating nsIDOMRanges in response to editor actions.
|
||||
*/
|
||||
|
||||
nsRangeUpdater::nsRangeUpdater() : mArray(), mLock(PR_FALSE) {}
|
||||
|
||||
nsRangeUpdater::~nsRangeUpdater()
|
||||
{
|
||||
// free any items in the array
|
||||
nsRangeStore *item;
|
||||
while ((item = (nsRangeStore*)mArray.ElementAt(0)))
|
||||
{
|
||||
delete item;
|
||||
mArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
nsRangeUpdater::RegisterRange(nsIDOMRange *aRange)
|
||||
{
|
||||
nsRangeStore *item = new nsRangeStore;
|
||||
if (!item) return nsnull;
|
||||
item->StoreRange(aRange);
|
||||
mArray.AppendElement(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMRange>
|
||||
nsRangeUpdater::ReclaimRange(void *aCookie)
|
||||
{
|
||||
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
|
||||
if (!item) return nsnull;
|
||||
nsCOMPtr<nsIDOMRange> outRange;
|
||||
item->GetRange(address_of(outRange));
|
||||
mArray.RemoveElement(aCookie);
|
||||
delete item;
|
||||
return outRange;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::DropRange(void *aCookie)
|
||||
{
|
||||
nsRangeStore *item = NS_STATIC_CAST(nsRangeStore*,aCookie);
|
||||
if (!item) return;
|
||||
mArray.RemoveElement(aCookie);
|
||||
delete item;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::RegisterRangeItem(nsRangeStore *aRangeItem)
|
||||
{
|
||||
if (!aRangeItem) return;
|
||||
mArray.AppendElement(aRangeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
nsRangeUpdater::DropRangeItem(nsRangeStore *aRangeItem)
|
||||
{
|
||||
if (!aRangeItem) return;
|
||||
mArray.RemoveElement(aRangeItem);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::RegisterSelectionState(nsSelectionState &aSelState)
|
||||
{
|
||||
PRInt32 i, theCount = aSelState.mArray.Count();
|
||||
if (theCount < 1) return NS_ERROR_FAILURE;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<theCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
|
||||
RegisterRangeItem(item);
|
||||
}
|
||||
|
||||
return NS_OK;;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DropSelectionState(nsSelectionState &aSelState)
|
||||
{
|
||||
PRInt32 i, theCount = aSelState.mArray.Count();
|
||||
if (theCount < 1) return NS_ERROR_FAILURE;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<theCount; i++)
|
||||
{
|
||||
item = (nsRangeStore*)aSelState.mArray.ElementAt(i);
|
||||
DropRangeItem(item);
|
||||
}
|
||||
|
||||
return NS_OK;;
|
||||
}
|
||||
|
||||
// gravity methods:
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aPosition))
|
||||
item->startOffset++;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aPosition))
|
||||
item->endOffset++;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjInsertNode(nsIDOMNode *aParent, PRInt32 aPosition)
|
||||
{
|
||||
return SelAdjCreateNode(aParent, aPosition);
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjDeleteNode(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
|
||||
item->startOffset--;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
|
||||
item->endOffset--;
|
||||
}
|
||||
// MOOSE: also check inside of aNode, expensive. But in theory, we shouldn't
|
||||
// actually hit this case in the usage i forsee for this.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjSplitNode(nsIDOMNode *aOldRightNode, PRInt32 aOffset, nsIDOMNode *aNewLeftNode)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aOldRightNode || !aNewLeftNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
PRInt32 offset;
|
||||
nsresult result = nsEditor::GetNodeLocation(aOldRightNode, address_of(parent), &offset);
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// first part is same as inserting aNewLeftnode
|
||||
result = SelAdjInsertNode(parent,offset-1);
|
||||
if (NS_FAILED(result)) return result;
|
||||
|
||||
// next step is to check for range enpoints inside aOldRightNode
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aOldRightNode)
|
||||
{
|
||||
if (item->startOffset > aOffset)
|
||||
{
|
||||
item->startOffset -= aOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->startNode = aNewLeftNode;
|
||||
}
|
||||
}
|
||||
if (item->endNode.get() == aOldRightNode)
|
||||
{
|
||||
if (item->endOffset > aOffset)
|
||||
{
|
||||
item->endOffset -= aOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->endNode = aNewLeftNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjJoinNodes(nsIDOMNode *aLeftNode,
|
||||
nsIDOMNode *aRightNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRInt32 aOldLeftNodeLength)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
if (!aLeftNode || !aRightNode || !aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// adjust endpoints in aParent
|
||||
if (item->startNode.get() == aParent)
|
||||
{
|
||||
if (item->startOffset > aOffset)
|
||||
{
|
||||
item->startOffset--;
|
||||
}
|
||||
else if (item->startOffset == aOffset)
|
||||
{
|
||||
// join keeps right hand node
|
||||
item->startNode = aRightNode;
|
||||
item->startOffset = aOldLeftNodeLength;
|
||||
}
|
||||
}
|
||||
if (item->endNode.get() == aParent)
|
||||
{
|
||||
if (item->endOffset > aOffset)
|
||||
{
|
||||
item->endOffset--;
|
||||
}
|
||||
else if (item->endOffset == aOffset)
|
||||
{
|
||||
// join keeps right hand node
|
||||
item->endNode = aRightNode;
|
||||
item->endOffset = aOldLeftNodeLength;
|
||||
}
|
||||
}
|
||||
// adjust endpoints in aRightNode
|
||||
if (item->startNode.get() == aRightNode)
|
||||
item->startOffset += aOldLeftNodeLength;
|
||||
if (item->endNode.get() == aRightNode)
|
||||
item->endOffset += aOldLeftNodeLength;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjInsertText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, const nsString &aString)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::SelAdjDeleteText(nsIDOMCharacterData *aTextNode, PRInt32 aOffset, PRInt32 aLength)
|
||||
{
|
||||
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillReplaceContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidReplaceContainer(nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aOriginalNode || !aNewNode) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aOriginalNode)
|
||||
item->startNode = aNewNode;
|
||||
if (item->endNode.get() == aOriginalNode)
|
||||
item->endNode = aNewNode;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillRemoveContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidRemoveContainer(nsIDOMNode *aNode, nsIDOMNode *aParent, PRInt32 aOffset, PRUint32 aNodeOrigLen)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aNode || !aParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (item->startNode.get() == aNode)
|
||||
{
|
||||
item->startNode = aParent;
|
||||
item->startOffset += aOffset;
|
||||
}
|
||||
if (item->endNode.get() == aNode)
|
||||
{
|
||||
item->endNode = aParent;
|
||||
item->endOffset += aOffset;
|
||||
}
|
||||
if ((item->startNode.get() == aParent) && (item->startOffset > aOffset))
|
||||
item->startOffset += (PRInt32)aNodeOrigLen-1;
|
||||
if ((item->endNode.get() == aParent) && (item->endOffset > aOffset))
|
||||
item->endOffset += (PRInt32)aNodeOrigLen-1;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillInsertContainer()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidInsertContainer()
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::WillMoveNode()
|
||||
{
|
||||
if (mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsRangeUpdater::DidMoveNode(nsIDOMNode *aOldParent, PRInt32 aOldOffset, nsIDOMNode *aNewParent, PRInt32 aNewOffset)
|
||||
{
|
||||
if (!mLock) return NS_ERROR_UNEXPECTED;
|
||||
mLock = PR_FALSE;
|
||||
|
||||
if (!aOldParent || !aNewParent) return NS_ERROR_NULL_POINTER;
|
||||
PRInt32 i, count = mArray.Count();
|
||||
if (!count) return NS_OK;
|
||||
|
||||
nsRangeStore *item;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
item = (nsRangeStore*)mArray.ElementAt(i);
|
||||
if (!item) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// like a delete in aOldParent
|
||||
if ((item->startNode.get() == aOldParent) && (item->startOffset > aOldOffset))
|
||||
item->startOffset--;
|
||||
if ((item->endNode.get() == aOldParent) && (item->endOffset > aOldOffset))
|
||||
item->endOffset--;
|
||||
|
||||
// and like an insert in aNewParent
|
||||
if ((item->startNode.get() == aNewParent) && (item->startOffset > aNewOffset))
|
||||
item->startOffset++;
|
||||
if ((item->endNode.get() == aNewParent) && (item->endOffset > aNewOffset))
|
||||
item->endOffset++;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* helper class for nsSelectionState. nsRangeStore stores range endpoints.
|
||||
*/
|
||||
|
||||
// DEBUG: PRInt32 nsRangeStore::n = 0;
|
||||
|
||||
nsRangeStore::nsRangeStore()
|
||||
{
|
||||
// DEBUG: n++; printf("range store alloc count=%d\n", n);
|
||||
}
|
||||
nsRangeStore::~nsRangeStore()
|
||||
{
|
||||
// DEBUG: n--; printf("range store alloc count=%d\n", n);
|
||||
}
|
||||
|
||||
nsresult nsRangeStore::StoreRange(nsIDOMRange *aRange)
|
||||
{
|
||||
if (!aRange) return NS_ERROR_NULL_POINTER;
|
||||
aRange->GetStartContainer(getter_AddRefs(startNode));
|
||||
aRange->GetEndContainer(getter_AddRefs(endNode));
|
||||
aRange->GetStartOffset(&startOffset);
|
||||
aRange->GetEndOffset(&endOffset);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsRangeStore::GetRange(nsCOMPtr<nsIDOMRange> *outRange)
|
||||
{
|
||||
if (!outRange) return NS_ERROR_NULL_POINTER;
|
||||
nsresult res = nsComponentManager::CreateInstance(kCRangeCID,
|
||||
nsnull,
|
||||
NS_GET_IID(nsIDOMRange),
|
||||
getter_AddRefs(*outRange));
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = (*outRange)->SetStart(startNode, startOffset);
|
||||
if(NS_FAILED(res)) return res;
|
||||
|
||||
res = (*outRange)->SetEnd(endNode, endOffset);
|
||||
return res;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidReplaceContainer()
|
||||
*/
|
||||
|
||||
class nsAutoReplaceContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mOriginalNode;
|
||||
nsIDOMNode *mNewNode;
|
||||
|
||||
public:
|
||||
nsAutoReplaceContainerSelNotify(nsRangeUpdater &aRangeUpdater, nsIDOMNode *aOriginalNode, nsIDOMNode *aNewNode) :
|
||||
mRU(aRangeUpdater)
|
||||
,mOriginalNode(aOriginalNode)
|
||||
,mNewNode(aNewNode)
|
||||
{
|
||||
mRU.WillReplaceContainer();
|
||||
}
|
||||
|
||||
~nsAutoReplaceContainerSelNotify()
|
||||
{
|
||||
mRU.DidReplaceContainer(mOriginalNode, mNewNode);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidRemoveContainer()
|
||||
*/
|
||||
|
||||
class nsAutoRemoveContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mNode;
|
||||
nsIDOMNode *mParent;
|
||||
PRInt32 mOffset;
|
||||
PRUint32 mNodeOrigLen;
|
||||
|
||||
public:
|
||||
nsAutoRemoveContainerSelNotify(nsRangeUpdater &aRangeUpdater,
|
||||
nsIDOMNode *aNode,
|
||||
nsIDOMNode *aParent,
|
||||
PRInt32 aOffset,
|
||||
PRUint32 aNodeOrigLen) :
|
||||
mRU(aRangeUpdater)
|
||||
,mNode(aNode)
|
||||
,mParent(aParent)
|
||||
,mOffset(aOffset)
|
||||
,mNodeOrigLen(aNodeOrigLen)
|
||||
{
|
||||
mRU.WillRemoveContainer();
|
||||
}
|
||||
|
||||
~nsAutoRemoveContainerSelNotify()
|
||||
{
|
||||
mRU.DidRemoveContainer(mNode, mParent, mOffset, mNodeOrigLen);
|
||||
}
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidInsertContainer()
|
||||
*/
|
||||
|
||||
class nsAutoInsertContainerSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
|
||||
public:
|
||||
nsAutoInsertContainerSelNotify(nsRangeUpdater &aRangeUpdater) :
|
||||
mRU(aRangeUpdater)
|
||||
{
|
||||
mRU.WillInsertContainer();
|
||||
}
|
||||
|
||||
~nsAutoInsertContainerSelNotify()
|
||||
{
|
||||
mRU.DidInsertContainer();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* another helper class for nsSelectionState. stack based class for doing
|
||||
* Will/DidMoveNode()
|
||||
*/
|
||||
|
||||
class nsAutoMoveNodeSelNotify
|
||||
{
|
||||
private:
|
||||
nsRangeUpdater &mRU;
|
||||
nsIDOMNode *mOldParent;
|
||||
nsIDOMNode *mNewParent;
|
||||
PRInt32 mOldOffset;
|
||||
PRInt32 mNewOffset;
|
||||
|
||||
public:
|
||||
nsAutoMoveNodeSelNotify(nsRangeUpdater &aRangeUpdater,
|
||||
nsIDOMNode *aOldParent,
|
||||
PRInt32 aOldOffset,
|
||||
nsIDOMNode *aNewParent,
|
||||
PRInt32 aNewOffset) :
|
||||
mRU(aRangeUpdater)
|
||||
,mOldParent(aOldParent)
|
||||
,mNewParent(aNewParent)
|
||||
,mOldOffset(aOldOffset)
|
||||
,mNewOffset(aNewOffset)
|
||||
{
|
||||
mRU.WillMoveNode();
|
||||
}
|
||||
|
||||
~nsAutoMoveNodeSelNotify()
|
||||
{
|
||||
mRU.DidMoveNode(mOldParent, mOldOffset, mNewParent, mNewOffset);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// nsEditor: base editor class implementation
|
||||
@@ -2606,7 +1875,7 @@ nsEditor::ForceCompositionEnd()
|
||||
#endif
|
||||
|
||||
#ifdef XP_UNIX
|
||||
if(mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
||||
if(mFlags & nsIPlaintextEditor::eEditorPasswordMask)
|
||||
return NS_OK;
|
||||
#endif
|
||||
|
||||
@@ -5059,7 +4328,6 @@ nsEditor::IsNextCharWhitespace(nsIDOMNode *aParentNode,
|
||||
textNode->GetLength(&strLength);
|
||||
if (strLength)
|
||||
{
|
||||
// you could use nsITextContent::IsOnlyWhitespace here
|
||||
textNode->SubstringData(0,1,tempString);
|
||||
*outIsSpace = nsCRT::IsAsciiSpace(tempString.First());
|
||||
*outIsNBSP = (tempString.First() == nbsp);
|
||||
@@ -5391,7 +4659,7 @@ nsresult nsEditor::EndUpdateViewBatch()
|
||||
|
||||
PRBool forceReflow = PR_TRUE;
|
||||
|
||||
if (flags & nsIHTMLEditor::eEditorDisableForcedReflowsMask)
|
||||
if (flags & nsIPlaintextEditor::eEditorDisableForcedReflowsMask)
|
||||
forceReflow = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
@@ -5401,7 +4669,7 @@ nsresult nsEditor::EndUpdateViewBatch()
|
||||
|
||||
PRUint32 updateFlag = NS_VMREFRESH_IMMEDIATE;
|
||||
|
||||
if (flags & nsIHTMLEditor::eEditorDisableForcedUpdatesMask)
|
||||
if (flags & nsIPlaintextEditor::eEditorDisableForcedUpdatesMask)
|
||||
updateFlag = NS_VMREFRESH_NO_SYNC;
|
||||
|
||||
#ifdef HACK_FORCE_REDRAW
|
||||
@@ -5482,9 +4750,129 @@ nsEditor::DeleteSelectionImpl(nsIEditor::EDirection aAction)
|
||||
return res;
|
||||
}
|
||||
|
||||
// XXX: error handling in this routine needs to be cleaned up!
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DeleteSelectionAndCreateNode(const nsString& aTag,
|
||||
nsIDOMNode ** aNewNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> parentSelectedNode;
|
||||
PRInt32 offsetOfNewNode;
|
||||
nsresult result = DeleteSelectionAndPrepareToCreateNode(parentSelectedNode,
|
||||
offsetOfNewNode);
|
||||
if (!NS_SUCCEEDED(result))
|
||||
return result;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
result = CreateNode(aTag, parentSelectedNode, offsetOfNewNode,
|
||||
getter_AddRefs(newNode));
|
||||
// XXX: ERROR_HANDLING check result, and make sure aNewNode is set correctly in success/failure cases
|
||||
*aNewNode = newNode;
|
||||
NS_IF_ADDREF(*aNewNode);
|
||||
|
||||
// we want the selection to be just after the new node
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
result = selection->Collapse(parentSelectedNode, offsetOfNewNode+1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Non-interface, protected methods */
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DeleteSelectionAndPrepareToCreateNode(nsCOMPtr<nsIDOMNode> &parentSelectedNode, PRInt32& offsetOfNewNode)
|
||||
{
|
||||
nsresult result=NS_ERROR_NOT_INITIALIZED;
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (!selection) return NS_ERROR_NULL_POINTER;
|
||||
|
||||
PRBool collapsed;
|
||||
result = selection->GetIsCollapsed(&collapsed);
|
||||
if (NS_SUCCEEDED(result) && !collapsed)
|
||||
{
|
||||
result = DeleteSelection(nsIEditor::eNone);
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
// get the new selection
|
||||
result = GetSelection(getter_AddRefs(selection));
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
#ifdef NS_DEBUG
|
||||
nsCOMPtr<nsIDOMNode>testSelectedNode;
|
||||
nsresult debugResult = selection->GetAnchorNode(getter_AddRefs(testSelectedNode));
|
||||
// no selection is ok.
|
||||
// if there is a selection, it must be collapsed
|
||||
if (testSelectedNode)
|
||||
{
|
||||
PRBool testCollapsed;
|
||||
debugResult = selection->GetIsCollapsed(&testCollapsed);
|
||||
NS_ASSERTION((NS_SUCCEEDED(result)), "couldn't get a selection after deletion");
|
||||
NS_ASSERTION(testCollapsed, "selection not reset after deletion");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// split the selected node
|
||||
PRInt32 offsetOfSelectedNode;
|
||||
result = selection->GetAnchorNode(getter_AddRefs(parentSelectedNode));
|
||||
if (NS_SUCCEEDED(result) && NS_SUCCEEDED(selection->GetAnchorOffset(&offsetOfSelectedNode)) && parentSelectedNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> selectedNode;
|
||||
PRUint32 selectedNodeContentCount=0;
|
||||
nsCOMPtr<nsIDOMCharacterData>selectedParentNodeAsText;
|
||||
selectedParentNodeAsText = do_QueryInterface(parentSelectedNode);
|
||||
|
||||
offsetOfNewNode = offsetOfSelectedNode;
|
||||
|
||||
/* if the selection is a text node, split the text node if necesary
|
||||
and compute where to put the new node
|
||||
*/
|
||||
if (selectedParentNodeAsText)
|
||||
{
|
||||
PRInt32 indexOfTextNodeInParent;
|
||||
selectedNode = do_QueryInterface(parentSelectedNode);
|
||||
selectedNode->GetParentNode(getter_AddRefs(parentSelectedNode));
|
||||
selectedParentNodeAsText->GetLength(&selectedNodeContentCount);
|
||||
GetChildOffset(selectedNode, parentSelectedNode, indexOfTextNodeInParent);
|
||||
|
||||
if ((offsetOfSelectedNode!=0) && (((PRUint32)offsetOfSelectedNode)!=selectedNodeContentCount))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> newSiblingNode;
|
||||
result = SplitNode(selectedNode, offsetOfSelectedNode, getter_AddRefs(newSiblingNode));
|
||||
// now get the node's offset in it's parent, and insert the new tag there
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
result = GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // determine where to insert the new node
|
||||
if (0==offsetOfSelectedNode) {
|
||||
offsetOfNewNode = indexOfTextNodeInParent; // insert new node as previous sibling to selection parent
|
||||
}
|
||||
else { // insert new node as last child
|
||||
GetChildOffset(selectedNode, parentSelectedNode, offsetOfNewNode);
|
||||
offsetOfNewNode++; // offsets are 0-based, and we need the index of the new node
|
||||
}
|
||||
}
|
||||
}
|
||||
// Here's where the new node was inserted
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
printf("InsertLineBreak into an empty document is not yet supported\n");
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::DoAfterDoTransaction(nsITransaction *aTxn)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user