From fb3a597e8a84820493d4da2c745308edabacaf11 Mon Sep 17 00:00:00 2001 From: "mjudge%netscape.com" Date: Fri, 19 Feb 1999 23:47:36 +0000 Subject: [PATCH] nsPresShell now listens to changes in the domselection. (also modified nsIEnumerator to use NS_IMETHOD instead of virtual nsresult). Added batching for selection changes. you can move the selection, do things then turn off batching for an update if necessary. also prevented circular referencing by adding listener removal to PresShell::endDocumentListening(sp) --- layout/base/nsFrameTraversal.cpp | 30 ++-- layout/base/nsIFrameSelection.h | 5 + layout/base/nsPresShell.cpp | 41 ++++- layout/base/public/nsIDOMSelection.h | 13 ++ layout/base/public/nsIDOMSelectionListener.h | 3 +- layout/base/public/nsIFrameSelection.h | 5 + layout/base/src/nsFrameTraversal.cpp | 30 ++-- layout/base/src/nsRangeList.cpp | 153 +++++++++++++------ layout/generic/nsFrame.cpp | 4 + layout/generic/nsTextFrame.cpp | 87 +++++++---- layout/html/base/src/nsFrame.cpp | 4 + layout/html/base/src/nsPresShell.cpp | 41 ++++- layout/html/base/src/nsTextFrame.cpp | 87 +++++++---- 13 files changed, 357 insertions(+), 146 deletions(-) diff --git a/layout/base/nsFrameTraversal.cpp b/layout/base/nsFrameTraversal.cpp index 65cce65547df..9883b7c64727 100644 --- a/layout/base/nsFrameTraversal.cpp +++ b/layout/base/nsFrameTraversal.cpp @@ -11,17 +11,17 @@ class nsFrameIterator: public nsIEnumerator public: NS_DECL_ISUPPORTS - virtual nsresult First(); + NS_IMETHOD First(); - virtual nsresult Last(); + NS_IMETHOD Last(); - virtual nsresult Next()=0; + NS_IMETHOD Next()=0; - virtual nsresult Prev()=0; + NS_IMETHOD Prev()=0; - virtual nsresult CurrentItem(nsISupports **aItem); + NS_IMETHOD CurrentItem(nsISupports **aItem); - virtual nsresult IsDone();//what does this mean??off edge? yes + NS_IMETHOD IsDone();//what does this mean??off edge? yes nsFrameIterator(); protected: @@ -60,9 +60,9 @@ public: nsLeafIterator(nsIFrame *start); private : - virtual nsresult Next(); + NS_IMETHOD Next(); - virtual nsresult Prev(); + NS_IMETHOD Prev(); }; @@ -127,7 +127,7 @@ nsFrameIterator::nsFrameIterator() -nsresult +NS_IMETHODIMP nsFrameIterator::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (NULL == aInstancePtr) { @@ -148,7 +148,7 @@ nsFrameIterator::QueryInterface(REFNSIID aIID, void** aInstancePtr) -nsresult +NS_IMETHODIMP nsFrameIterator::CurrentItem(nsISupports **aItem) { if (!aItem) @@ -159,7 +159,7 @@ nsFrameIterator::CurrentItem(nsISupports **aItem) -nsresult +NS_IMETHODIMP nsFrameIterator::IsDone()//what does this mean??off edge? yes { if (mOffEdge != 0) @@ -169,7 +169,7 @@ nsFrameIterator::IsDone()//what does this mean??off edge? yes -nsresult +NS_IMETHODIMP nsFrameIterator::First() { mCurrent = mStart; @@ -178,7 +178,7 @@ nsFrameIterator::First() -nsresult +NS_IMETHODIMP nsFrameIterator::Last() { return NS_ERROR_FAILURE; @@ -198,7 +198,7 @@ nsLeafIterator::nsLeafIterator(nsIFrame *aStart) -nsresult +NS_IMETHODIMP nsLeafIterator::Next() { //recursive-oid method to get next frame @@ -243,7 +243,7 @@ nsLeafIterator::Next() -nsresult +NS_IMETHODIMP nsLeafIterator::Prev() { //recursive-oid method to get prev frame diff --git a/layout/base/nsIFrameSelection.h b/layout/base/nsIFrameSelection.h index 7344ed919410..b6a3288a262a 100644 --- a/layout/base/nsIFrameSelection.h +++ b/layout/base/nsIFrameSelection.h @@ -66,6 +66,11 @@ public: */ NS_IMETHOD ResetSelection(nsIFocusTracker *aTracker, nsIFrame *aStartFrame) = 0; + /** EnableFrameNotification + * mutch like start batching, except all dirty calls are ignored. no notifications will go + * out until enableNotifications with a PR_TRUE is called + */ + NS_IMETHOD EnableFrameNotification(PRBool aEnable) = 0; }; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index f5353399a619..6ef31cb3078e 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -56,6 +56,8 @@ #include "nsCaretProperties.h" #include "nsIDOMHTMLDocument.h" #include "nsIScrollableView.h" +#include "nsIDOMSelectionListener.h" + static PRBool gsNoisyRefs = PR_FALSE; #undef NOISY @@ -173,6 +175,7 @@ static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); static NS_DEFINE_IID(kIDOMRangeIID, NS_IDOMRANGE_IID); static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID); static NS_DEFINE_IID(kIFocusTrackerIID, NS_IFOCUSTRACKER_IID); +static NS_DEFINE_IID(kIDomSelectionListenerIID, NS_IDOMSELECTIONLISTENER_IID); static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID); static NS_DEFINE_IID(kICaretIID, NS_ICARET_IID); static NS_DEFINE_IID(kICaretID, NS_ICARET_IID); @@ -181,8 +184,8 @@ static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID); static NS_DEFINE_IID(kIScrollableViewIID, NS_ISCROLLABLEVIEW_IID); class PresShell : public nsIPresShell, public nsIViewObserver, - private nsIDocumentObserver, public nsIFocusTracker - + private nsIDocumentObserver, public nsIFocusTracker, + public nsIDOMSelectionListener { public: PresShell(); @@ -310,6 +313,8 @@ public: NS_IMETHOD GetCaret(nsICaret **outCaret); NS_IMETHOD RefreshCaret(); + // nsIDOMSelectionListener interface + NS_IMETHOD NotifySelectionChanged(); // implementation void HandleCantRenderReplacedElementEvent(nsIFrame* aFrame); @@ -467,6 +472,12 @@ PresShell::QueryInterface(const nsIID& aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(kIDomSelectionListenerIID)) { + nsIDOMSelectionListener* tmp = this; + *aInstancePtr = (void*) tmp; + NS_ADDREF_THIS(); + return NS_OK; + } if (aIID.Equals(kISupportsIID)) { nsIPresShell* tmp = this; nsISupports* tmp2 = tmp; @@ -543,7 +554,7 @@ PresShell::Init(nsIDocument* aDocument, getter_AddRefs(mSelection)); if (!NS_SUCCEEDED(result)) return result; - + domselection->AddSelectionListener(this);//possible circular reference // XXX This code causes the document object (and the entire content model) to be leaked... #if 0 nsCOMPtrrange; @@ -766,6 +777,16 @@ PresShell::EndObservingDocument() if (nsnull != mDocument) { mDocument->RemoveObserver(this); } + if (mSelection){ + nsCOMPtr domselection; + nsresult result; + domselection = do_QueryInterface(mSelection , &result); + if (NS_FAILED(result)) + return result; + if (!domselection) + return NS_ERROR_UNEXPECTED; + domselection->RemoveSelectionListener(this); + } return NS_OK; } @@ -939,6 +960,17 @@ NS_IMETHODIMP PresShell::RefreshCaret() return NS_OK; } +/*implementation of the nsIDOMSelectionListener + it will invoke the resetselection to update the presentation shell's frames +*/ +NS_IMETHODIMP PresShell::NotifySelectionChanged() +{ + if (!mSelection) + return NS_ERROR_NULL_POINTER; + mSelection->ResetSelection(this, mRootFrame); + return NS_ERROR_NULL_POINTER; +} + nsresult PresShell::DisableCaret() { if (mCaret) @@ -1757,7 +1789,10 @@ PresShell::HandleEvent(nsIView *aView, if (nsnull != frame) { if (mSelection && mFocusEventFrame && aEvent->eventStructType == NS_KEY_EVENT) { + mSelection->EnableFrameNotification(PR_FALSE); mSelection->HandleKeyEvent((nsIFocusTracker *)this, aEvent, mFocusEventFrame); + mSelection->EnableFrameNotification(PR_TRUE); //prevents secondary reset selection called since + //we are a listener now. } frame->GetFrameForPoint(aEvent->point, &mCurrentEventFrame); if (nsnull != mCurrentEventFrame) { diff --git a/layout/base/public/nsIDOMSelection.h b/layout/base/public/nsIDOMSelection.h index 4d61241795c1..e9670774d280 100644 --- a/layout/base/public/nsIDOMSelection.h +++ b/layout/base/public/nsIDOMSelection.h @@ -84,6 +84,19 @@ public: NS_IMETHOD AddSelectionListener(nsIDOMSelectionListener* inNewListener) = 0; NS_IMETHOD RemoveSelectionListener(nsIDOMSelectionListener* inListenerToRemove) = 0; + /** StartBatchChanges + * will return NS_OK if there is no previous unmatched StartBatchChanges Called + * calling this multiple times should have no effect. + */ + NS_IMETHOD StartBatchChanges() = 0; + + /** EndBatchChanges + * will return NS_OK if there was a StartBatch Changes Called + * calling this multiple times should have no effect. will return NS_ERROR_FAILURE + * after the first call. if any changes took place, it will then immediately notify all + */ + NS_IMETHOD EndBatchChanges() = 0; + }; diff --git a/layout/base/public/nsIDOMSelectionListener.h b/layout/base/public/nsIDOMSelectionListener.h index c719befc3162..24b264a267f7 100644 --- a/layout/base/public/nsIDOMSelectionListener.h +++ b/layout/base/public/nsIDOMSelectionListener.h @@ -36,13 +36,14 @@ { 0xa6cf90e2, 0x15b3, 0x11d2, \ { 0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32} } + + // Selection interface class nsIDOMSelectionListener : public nsISupports { public: static const nsIID& IID() { static nsIID iid = NS_IDOMSELECTIONLISTENER_IID; return iid; } - NS_IMETHOD NotifySelectionChanged() = 0; }; diff --git a/layout/base/public/nsIFrameSelection.h b/layout/base/public/nsIFrameSelection.h index 7344ed919410..b6a3288a262a 100644 --- a/layout/base/public/nsIFrameSelection.h +++ b/layout/base/public/nsIFrameSelection.h @@ -66,6 +66,11 @@ public: */ NS_IMETHOD ResetSelection(nsIFocusTracker *aTracker, nsIFrame *aStartFrame) = 0; + /** EnableFrameNotification + * mutch like start batching, except all dirty calls are ignored. no notifications will go + * out until enableNotifications with a PR_TRUE is called + */ + NS_IMETHOD EnableFrameNotification(PRBool aEnable) = 0; }; diff --git a/layout/base/src/nsFrameTraversal.cpp b/layout/base/src/nsFrameTraversal.cpp index 65cce65547df..9883b7c64727 100644 --- a/layout/base/src/nsFrameTraversal.cpp +++ b/layout/base/src/nsFrameTraversal.cpp @@ -11,17 +11,17 @@ class nsFrameIterator: public nsIEnumerator public: NS_DECL_ISUPPORTS - virtual nsresult First(); + NS_IMETHOD First(); - virtual nsresult Last(); + NS_IMETHOD Last(); - virtual nsresult Next()=0; + NS_IMETHOD Next()=0; - virtual nsresult Prev()=0; + NS_IMETHOD Prev()=0; - virtual nsresult CurrentItem(nsISupports **aItem); + NS_IMETHOD CurrentItem(nsISupports **aItem); - virtual nsresult IsDone();//what does this mean??off edge? yes + NS_IMETHOD IsDone();//what does this mean??off edge? yes nsFrameIterator(); protected: @@ -60,9 +60,9 @@ public: nsLeafIterator(nsIFrame *start); private : - virtual nsresult Next(); + NS_IMETHOD Next(); - virtual nsresult Prev(); + NS_IMETHOD Prev(); }; @@ -127,7 +127,7 @@ nsFrameIterator::nsFrameIterator() -nsresult +NS_IMETHODIMP nsFrameIterator::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (NULL == aInstancePtr) { @@ -148,7 +148,7 @@ nsFrameIterator::QueryInterface(REFNSIID aIID, void** aInstancePtr) -nsresult +NS_IMETHODIMP nsFrameIterator::CurrentItem(nsISupports **aItem) { if (!aItem) @@ -159,7 +159,7 @@ nsFrameIterator::CurrentItem(nsISupports **aItem) -nsresult +NS_IMETHODIMP nsFrameIterator::IsDone()//what does this mean??off edge? yes { if (mOffEdge != 0) @@ -169,7 +169,7 @@ nsFrameIterator::IsDone()//what does this mean??off edge? yes -nsresult +NS_IMETHODIMP nsFrameIterator::First() { mCurrent = mStart; @@ -178,7 +178,7 @@ nsFrameIterator::First() -nsresult +NS_IMETHODIMP nsFrameIterator::Last() { return NS_ERROR_FAILURE; @@ -198,7 +198,7 @@ nsLeafIterator::nsLeafIterator(nsIFrame *aStart) -nsresult +NS_IMETHODIMP nsLeafIterator::Next() { //recursive-oid method to get next frame @@ -243,7 +243,7 @@ nsLeafIterator::Next() -nsresult +NS_IMETHODIMP nsLeafIterator::Prev() { //recursive-oid method to get prev frame diff --git a/layout/base/src/nsRangeList.cpp b/layout/base/src/nsRangeList.cpp index 4d98584e86e6..df6b5d996d05 100644 --- a/layout/base/src/nsRangeList.cpp +++ b/layout/base/src/nsRangeList.cpp @@ -74,6 +74,7 @@ public: NS_IMETHOD HandleKeyEvent(nsIFocusTracker *aTracker, nsGUIEvent *aGuiEvent, nsIFrame *aFrame); NS_IMETHOD TakeFocus(nsIFocusTracker *aTracker, nsIFrame *aFrame, PRInt32 aOffset, PRInt32 aContentOffset, PRBool aContinueSelection); NS_IMETHOD ResetSelection(nsIFocusTracker *aTracker, nsIFrame *aStartFrame); + NS_IMETHOD EnableFrameNotification(PRBool aEnable){mNotifyFrames = aEnable; return NS_OK;} /*END nsIFrameSelection interfacse*/ /*BEGIN nsIDOMSelection interface implementations*/ @@ -88,6 +89,8 @@ public: NS_IMETHOD AddSelectionListener(nsIDOMSelectionListener* inNewListener); NS_IMETHOD RemoveSelectionListener(nsIDOMSelectionListener* inListenerToRemove); + NS_IMETHOD StartBatchChanges(); + NS_IMETHOD EndBatchChanges(); /*END nsIDOMSelection interface implementations*/ @@ -114,6 +117,9 @@ private: nsIDOMNode* GetFocusNode(); //where is the carret PRInt32 GetFocusOffset(); void setFocus(nsIDOMNode*, PRInt32); + PRBool GetBatching(){return mBatching;} + PRBool GetNotifyFrames(){return mNotifyFrames;} + void SetDirty(PRBool aDirty=PR_TRUE){if (mBatching) mChangesDuringBatching = aDirty;} nsresult NotifySelectionListeners(); // add parameters to say collapsed etc? @@ -124,8 +130,13 @@ private: nsCOMPtr mFocusNode; //where is the carret PRInt32 mFocusOffset; - nsCOMPtr mSelectionListeners; + //batching + PRBool mBatching; + PRBool mChangesDuringBatching; + PRBool mNotifyFrames; + + nsCOMPtr mSelectionListeners; }; class nsRangeListIterator : public nsIEnumerator @@ -136,21 +147,21 @@ see the nsIEnumerator for more details*/ NS_DECL_ISUPPORTS - virtual nsresult First(); + NS_IMETHOD First(); - virtual nsresult Last(); + NS_IMETHOD Last(); - virtual nsresult Next(); + NS_IMETHOD Next(); - virtual nsresult Prev(); + NS_IMETHOD Prev(); - virtual nsresult CurrentItem(nsISupports **aRange); + NS_IMETHOD CurrentItem(nsISupports **aRange); - virtual nsresult IsDone(); + NS_IMETHOD IsDone(); /*END nsIEnumerator interfaces*/ /*BEGIN Helper Methods*/ - virtual nsresult CurrentItem(nsIDOMRange **aRange); + NS_IMETHOD CurrentItem(nsIDOMRange **aRange); /*END Helper Methods*/ private: friend class nsRangeList; @@ -207,7 +218,7 @@ nsRangeListIterator::~nsRangeListIterator() -nsresult +NS_IMETHODIMP nsRangeListIterator::Next() { mIndex++; @@ -218,7 +229,7 @@ nsRangeListIterator::Next() -nsresult +NS_IMETHODIMP nsRangeListIterator::Prev() { mIndex--; @@ -229,7 +240,7 @@ nsRangeListIterator::Prev() -nsresult +NS_IMETHODIMP nsRangeListIterator::First() { if (!mRangeList) @@ -240,7 +251,7 @@ nsRangeListIterator::First() -nsresult +NS_IMETHODIMP nsRangeListIterator::Last() { if (!mRangeList) @@ -251,7 +262,7 @@ nsRangeListIterator::Last() -nsresult +NS_IMETHODIMP nsRangeListIterator::CurrentItem(nsISupports **aItem) { if (!aItem) @@ -265,7 +276,7 @@ nsRangeListIterator::CurrentItem(nsISupports **aItem) -nsresult +NS_IMETHODIMP nsRangeListIterator::CurrentItem(nsIDOMRange **aItem) { if (!aItem) @@ -279,7 +290,7 @@ nsRangeListIterator::CurrentItem(nsIDOMRange **aItem) -nsresult +NS_IMETHODIMP nsRangeListIterator::IsDone() { if (mIndex >= 0 && mIndex < (PRInt32)mRangeList->mRangeArray->Count() ) { @@ -296,7 +307,7 @@ NS_IMPL_RELEASE(nsRangeListIterator) -nsresult +NS_IMETHODIMP nsRangeListIterator::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (NULL == aInstancePtr) { @@ -341,6 +352,9 @@ nsRangeList::nsRangeList() NS_INIT_REFCNT(); NS_NewISupportsArray(getter_AddRefs(mRangeArray)); NS_NewISupportsArray(getter_AddRefs(mSelectionListeners)); + mBatching = PR_FALSE; + mChangesDuringBatching = PR_FALSE; + mNotifyFrames = PR_TRUE; } @@ -376,7 +390,7 @@ NS_IMPL_ADDREF(nsRangeList) NS_IMPL_RELEASE(nsRangeList) -nsresult +NS_IMETHODIMP nsRangeList::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (NULL == aInstancePtr) { @@ -532,33 +546,37 @@ nsRangeList::HandleKeyEvent(nsIFocusTracker *aTracker, nsGUIEvent *aGuiEvent, ns if (!domnode) return NS_ERROR_FAILURE; - //DUMMY CHECKING. CAN BE REMOVED. MAYBE IT WILL FOR SPEED PURPOSES PRBool selected; PRInt32 beginoffset; PRInt32 endoffset; PRInt32 contentoffset; - //check to make sure the frame REALLY has the focus point. - if (NS_SUCCEEDED(aFrame->GetSelected(&selected,&beginoffset,&endoffset, &contentoffset))){ - if (domnode != mFocusNode || (contentoffset + endoffset) != mFocusOffset) //not really the insertion frame - return NS_ERROR_FAILURE; + nsresult result = NS_OK; + result = aFrame->GetSelected(&selected,&beginoffset,&endoffset, &contentoffset); + if (NS_FAILED(result)){ + return result; } nsKeyEvent *keyEvent = (nsKeyEvent *)aGuiEvent; //this is ok. It really is a keyevent nsIFrame *resultFrame; PRInt32 frameOffset; PRInt32 contentOffset; + PRInt32 offsetused = beginoffset; switch (keyEvent->keyCode){ case nsIDOMEvent::VK_LEFT : //we need to look for the previous PAINTED location to move the cursor to. printf("debug vk left\n"); - if (NS_SUCCEEDED(aFrame->PeekOffset(eSelectCharacter, eDirPrevious, endoffset, &resultFrame, &frameOffset, &contentOffset)) && resultFrame){ + if (endoffset < beginoffset) + offsetused = endoffset; + if (NS_SUCCEEDED(aFrame->PeekOffset(eSelectCharacter, eDirPrevious, offsetused, &resultFrame, &frameOffset, &contentOffset)) && resultFrame){ return TakeFocus(aTracker, resultFrame, frameOffset, contentOffset, keyEvent->isShift); } break; case nsIDOMEvent::VK_RIGHT : //we need to look for the next PAINTED location to move the cursor to. printf("debug vk right\n"); - if (NS_SUCCEEDED(aFrame->PeekOffset(eSelectCharacter, eDirNext, endoffset, &resultFrame, &frameOffset, &contentOffset)) && resultFrame){ + if (endoffset > beginoffset) + offsetused = endoffset; + if (NS_SUCCEEDED(aFrame->PeekOffset(eSelectCharacter, eDirNext, offsetused, &resultFrame, &frameOffset, &contentOffset)) && resultFrame){ return TakeFocus(aTracker, resultFrame, frameOffset, contentOffset, keyEvent->isShift); } case nsIDOMEvent::VK_UP : @@ -705,6 +723,8 @@ nsRangeList::TakeFocus(nsIFocusTracker *aTracker, nsIFrame *aFrame, PRInt32 aOff { if (!aTracker || !aFrame) return NS_ERROR_NULL_POINTER; + if (GetBatching()) + return NS_ERROR_FAILURE; //HACKHACKHACK nsCOMPtr content; nsCOMPtr domNode; @@ -741,7 +761,12 @@ nsRangeList::TakeFocus(nsIFocusTracker *aTracker, nsIFrame *aFrame, PRInt32 aOff direction = PR_TRUE; //slecting "english" right aFrame->SetSelected(PR_TRUE,aOffset,aOffset,PR_FALSE); aTracker->SetFocus(aFrame,aFrame); + PRBool batching = mBatching;//hack to use the collapse code. + PRBool changes = mChangesDuringBatching; + mBatching = PR_TRUE; Collapse(domNode, aContentOffset + aOffset); + mBatching = batching; + mChangesDuringBatching = changes; } else { if (aFrame == frame){ //drag to same frame @@ -908,6 +933,12 @@ nsRangeList::ResetSelection(nsIFocusTracker *aTracker, nsIFrame *aStartFrame) PRInt32 endOffset; nsIFrame *result; nsCOMPtr range; + if (!GetNotifyFrames()) + return NS_OK; + if (GetBatching()){ + SetDirty(); + return NS_OK; + } //we will need to check if any "side" is the anchor and send a direction order to the frames. if (!mRangeArray) return NS_ERROR_FAILURE; @@ -985,7 +1016,7 @@ NS_METHOD nsRangeList::AddSelectionListener(nsIDOMSelectionListener* inNewListen -NS_METHOD nsRangeList::RemoveSelectionListener(nsIDOMSelectionListener* inListenerToRemove) +NS_IMETHODIMP nsRangeList::RemoveSelectionListener(nsIDOMSelectionListener* inListenerToRemove) { if (!mSelectionListeners) return NS_ERROR_FAILURE; @@ -996,26 +1027,58 @@ NS_METHOD nsRangeList::RemoveSelectionListener(nsIDOMSelectionListener* inListen } + +NS_IMETHODIMP nsRangeList::StartBatchChanges() +{ + nsresult result(NS_OK); + if (PR_TRUE == mBatching) + result = NS_ERROR_FAILURE; + mBatching = PR_TRUE; + return result; +} + + + +NS_IMETHODIMP nsRangeList::EndBatchChanges() +{ + nsresult result(NS_OK); + if (PR_FALSE == mBatching) + result = NS_ERROR_FAILURE; + mBatching = PR_FALSE; + if (mChangesDuringBatching){ + mChangesDuringBatching = PR_FALSE; + NotifySelectionListeners(); + } + return result; +} + + + nsresult nsRangeList::NotifySelectionListeners() { if (!mSelectionListeners) return NS_ERROR_FAILURE; - + + if (GetBatching()){ + SetDirty(); + return NS_OK; + } for (PRInt32 i = 0; i < mSelectionListeners->Count();i++) { - nsCOMPtr thisEntry(dont_QueryInterface(mSelectionListeners->ElementAt(i))); - nsCOMPtr thisListener(do_QueryInterface(thisEntry)); + nsCOMPtr thisListener; + thisListener = do_QueryInterface(mSelectionListeners->ElementAt(i)); if (thisListener) thisListener->NotifySelectionChanged(); } - return NS_OK; } //END nsIFrameSelection methods //BEGIN nsIDOMSelection interface implementations +#ifdef XP_MAC #pragma mark - +#endif /** ClearSelection zeroes the selection */ @@ -1047,13 +1110,15 @@ nsRangeList::AddRange(nsIDOMRange* aRange) // Also need to notify the frames! } + + /* * Collapse sets the whole selection to be one point. */ NS_IMETHODIMP nsRangeList::Collapse(nsIDOMNode* aParentNode, PRInt32 aOffset) { - nsresult res; + nsresult result; // Delete all of the current ranges if (!mRangeArray) @@ -1061,27 +1126,29 @@ nsRangeList::Collapse(nsIDOMNode* aParentNode, PRInt32 aOffset) Clear(); nsCOMPtr range; - res = nsRepository::CreateInstance(kRangeCID, nsnull, + result = nsRepository::CreateInstance(kRangeCID, nsnull, kIDOMRangeIID, getter_AddRefs(range)); - if (!NS_SUCCEEDED(res)) - return res; + if (NS_FAILED(result)) + return result; - if (! range) + if (! range){ + NS_ASSERTION(PR_FALSE,"Create Instance Failed nsRangeList::Collapse"); return NS_ERROR_UNEXPECTED; - res = range->SetEnd(aParentNode, aOffset); - if (!NS_SUCCEEDED(res)) - return res; - res = range->SetStart(aParentNode, aOffset); - if (!NS_SUCCEEDED(res)) - return res; + } + result = range->SetEnd(aParentNode, aOffset); + if (NS_FAILED(result)) + return result; + result = range->SetStart(aParentNode, aOffset); + if (NS_FAILED(result)) + return result; setAnchor(aParentNode, aOffset); setFocus(aParentNode, aOffset); - res = AddItem(range); - if (!NS_SUCCEEDED(res)) - return res; + result = AddItem(range); + if (NS_FAILED(result)) + return result; return NotifySelectionListeners(); } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 0bd3701787a1..0d5707ad75f2 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -719,7 +719,9 @@ nsFrame::HandlePress(nsIPresContext& aPresContext, nsIFrameSelection *frameselection = nsnull; if (NS_SUCCEEDED(selection->QueryInterface(kIFrameSelection, (void **)&frameselection))) { + frameselection->EnableFrameNotification(PR_FALSE); frameselection->TakeFocus(tracker, this, startPos, contentOffset, PR_FALSE); + frameselection->EnableFrameNotification(PR_TRUE);//prevent cyclic call to reset selection. NS_RELEASE(frameselection); } NS_RELEASE(tracker); @@ -760,7 +762,9 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsIPresContext& aPresContext, if (NS_SUCCEEDED(shell->QueryInterface(kIFocusTracker,(void **)&tracker))) { nsIFrameSelection* frameselection; if (NS_SUCCEEDED(selection->QueryInterface(kIFrameSelection, (void **)&frameselection))) { + frameselection->EnableFrameNotification(PR_FALSE); frameselection->TakeFocus(tracker, this, startPos, contentOffset, PR_TRUE); //TRUE IS THE DIFFERENCE + frameselection->EnableFrameNotification(PR_TRUE);//prevent cyclic call to reset selection. NS_RELEASE(frameselection); } NS_RELEASE(tracker); diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 8ea73f0c363d..862a892a2f9b 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -870,8 +870,7 @@ TextFrame::PaintUnicodeText(nsIPresContext& aPresContext, CURSOR_COLOR); #endif } - else - { + else { nscoord x = dx; if (selectionOffset) { @@ -1142,7 +1141,6 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, shell->GetDocument(getter_AddRefs(doc)); PRBool displaySelection; displaySelection = doc->GetDisplaySelection(); - displaySelection = PR_FALSE; // Make enough space to transform PRUnichar wordBufMem[WORD_BUF_SIZE]; @@ -1151,7 +1149,7 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, PRInt32* ip = indicies; PRUnichar* paintBuf = paintBufMem; if (mContentLength > TEXT_BUF_SIZE) { - ip = new PRInt32[mContentLength]; + ip = new PRInt32[mContentLength+1]; paintBuf = new PRUnichar[mContentLength]; } nscoord width = mRect.width; @@ -1162,6 +1160,7 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, aTextStyle.mNumSpaces = PrepareUnicodeText(tx, displaySelection ? ip : nsnull, paintBuf, textLength, width); + ip[mContentLength] = ip[mContentLength-1]+1; //must set up last one for selection beyond edge if (mRect.width > mComputedWidth) { if (0 != aTextStyle.mNumSpaces) { nscoord extra = mRect.width - mComputedWidth; @@ -1182,18 +1181,33 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, PRUnichar* text = paintBuf; if (0 != textLength) { - if (!displaySelection) { + if (!displaySelection || !mSelected || mSelectionOffset > mContentLength) { // When there is no selection showing, use the fastest and // simplest rendering approach RenderString(aRenderingContext, aStyleContext, aTextStyle, text, textLength, dx, dy, width); } else { - SelectionInfo si; -// ComputeSelectionInfo(aRenderingContext, doc, ip, textLength, si); - nscoord textWidth; - if (si.mEmptySelection) { + if (mSelectionOffset < 0) + mSelectionOffset = 0; + if (mSelectionEnd < 0) + mSelectionEnd = mContentLength; + if (mSelectionEnd > mContentLength) + mSelectionEnd = mContentLength; + if (mSelectionOffset > mContentLength) + mSelectionOffset = mContentLength; + PRInt32 selectionEnd = mSelectionEnd; + PRInt32 selectionOffset = mSelectionOffset; + if (mSelectionEnd < mSelectionOffset) + { + selectionEnd = mSelectionOffset; + selectionOffset = mSelectionEnd; + } + //where are the selection points "really" + selectionOffset = ip[selectionOffset] - mContentOffset; + selectionEnd = ip[selectionEnd] - mContentOffset; + if (selectionOffset == selectionEnd){ RenderString(aRenderingContext, aStyleContext, aTextStyle, text, textLength, dx, dy, width); @@ -1202,7 +1216,7 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, #ifdef SHOW_SELECTION_CURSOR GetWidth(aRenderingContext, aTextStyle, - text, PRUint32(si.mStartOffset), textWidth); + text, PRUint32(selectionOffset), textWidth); RenderSelectionCursor(aRenderingContext, dx + textWidth, dy, mRect.height, CURSOR_COLOR); @@ -1211,21 +1225,21 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, else { nscoord x = dx; - if (0 != si.mStartOffset) { + if (selectionOffset) { // Render first (unselected) section GetWidth(aRenderingContext, aTextStyle, - text, PRUint32(si.mStartOffset), + text, PRUint32(selectionOffset), textWidth); RenderString(aRenderingContext, aStyleContext, aTextStyle, - text, si.mStartOffset, + text, selectionOffset, x, dy, textWidth); x += textWidth; } - PRInt32 secondLen = si.mEndOffset - si.mStartOffset; + PRInt32 secondLen = selectionEnd - selectionOffset; if (0 != secondLen) { // Get the width of the second (selected) section GetWidth(aRenderingContext, aTextStyle, - text + si.mStartOffset, + text + selectionOffset, PRUint32(secondLen), textWidth); // Render second (selected) section @@ -1233,21 +1247,24 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, aRenderingContext.FillRect(x, dy, textWidth, mRect.height); aRenderingContext.SetColor(aTextStyle.mSelectionTextColor); RenderString(aRenderingContext, aStyleContext, aTextStyle, - text + si.mStartOffset, secondLen, + text + selectionOffset, secondLen, x, dy, textWidth); aRenderingContext.SetColor(aTextStyle.mColor->mColor); x += textWidth; } - if (textLength != si.mEndOffset) { - PRInt32 thirdLen = textLength - si.mEndOffset; + if (textLength != selectionEnd) { + PRInt32 thirdLen = textLength - selectionEnd; // Render third (unselected) section - GetWidth(aRenderingContext, aTextStyle, - text + si.mEndOffset, PRUint32(thirdLen), - textWidth); - RenderString(aRenderingContext, aStyleContext, aTextStyle, - text + si.mEndOffset, - thirdLen, x, dy, textWidth); + if (thirdLen > 0) //Text length is not negative or zero + { + GetWidth(aRenderingContext, aTextStyle, + text + selectionOffset, PRUint32(thirdLen), + textWidth); + RenderString(aRenderingContext, aStyleContext, aTextStyle, + text + selectionEnd, + thirdLen, x, dy, textWidth); + } } } } @@ -1298,7 +1315,6 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, displaySelection ? ip : nsnull, rawPaintBuf, textLength, width); ip[mContentLength] = ip[mContentLength-1]+1; //must set up last one for selection beyond edge - // Translate unicode data into ascii for rendering char* dst = paintBuf; char* end = dst + textLength; @@ -1347,9 +1363,10 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, // aRenderingContext.GetWidth(text, PRUint32(si.mStartOffset), textWidth); shell->RefreshCaret(); - + #ifdef SHOW_SELECTION_CURSOR aRenderingContext.GetWidth(text, PRUint32(selectionOffset), textWidth); + RenderSelectionCursor(aRenderingContext, dx + textWidth, dy, mRect.height, CURSOR_COLOR); @@ -1389,13 +1406,17 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, if (textLength != selectionEnd) { PRInt32 thirdLen = textLength - selectionEnd; - // Render third (unselected) section - aRenderingContext.GetWidth(text + selectionEnd, PRUint32(thirdLen), - textWidth); - aRenderingContext.DrawString(text + selectionEnd, - PRUint32(thirdLen), x, dy); - PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle, - x, dy, textWidth); + if (thirdLen > 0) //Text length is not negative or zero + { + + // Render third (unselected) section + aRenderingContext.GetWidth(text + selectionEnd, PRUint32(thirdLen), + textWidth); + aRenderingContext.DrawString(text + selectionEnd, + PRUint32(thirdLen), x, dy); + PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle, + x, dy, textWidth); + } } } } diff --git a/layout/html/base/src/nsFrame.cpp b/layout/html/base/src/nsFrame.cpp index 0bd3701787a1..0d5707ad75f2 100644 --- a/layout/html/base/src/nsFrame.cpp +++ b/layout/html/base/src/nsFrame.cpp @@ -719,7 +719,9 @@ nsFrame::HandlePress(nsIPresContext& aPresContext, nsIFrameSelection *frameselection = nsnull; if (NS_SUCCEEDED(selection->QueryInterface(kIFrameSelection, (void **)&frameselection))) { + frameselection->EnableFrameNotification(PR_FALSE); frameselection->TakeFocus(tracker, this, startPos, contentOffset, PR_FALSE); + frameselection->EnableFrameNotification(PR_TRUE);//prevent cyclic call to reset selection. NS_RELEASE(frameselection); } NS_RELEASE(tracker); @@ -760,7 +762,9 @@ NS_IMETHODIMP nsFrame::HandleDrag(nsIPresContext& aPresContext, if (NS_SUCCEEDED(shell->QueryInterface(kIFocusTracker,(void **)&tracker))) { nsIFrameSelection* frameselection; if (NS_SUCCEEDED(selection->QueryInterface(kIFrameSelection, (void **)&frameselection))) { + frameselection->EnableFrameNotification(PR_FALSE); frameselection->TakeFocus(tracker, this, startPos, contentOffset, PR_TRUE); //TRUE IS THE DIFFERENCE + frameselection->EnableFrameNotification(PR_TRUE);//prevent cyclic call to reset selection. NS_RELEASE(frameselection); } NS_RELEASE(tracker); diff --git a/layout/html/base/src/nsPresShell.cpp b/layout/html/base/src/nsPresShell.cpp index f5353399a619..6ef31cb3078e 100644 --- a/layout/html/base/src/nsPresShell.cpp +++ b/layout/html/base/src/nsPresShell.cpp @@ -56,6 +56,8 @@ #include "nsCaretProperties.h" #include "nsIDOMHTMLDocument.h" #include "nsIScrollableView.h" +#include "nsIDOMSelectionListener.h" + static PRBool gsNoisyRefs = PR_FALSE; #undef NOISY @@ -173,6 +175,7 @@ static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); static NS_DEFINE_IID(kIDOMRangeIID, NS_IDOMRANGE_IID); static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID); static NS_DEFINE_IID(kIFocusTrackerIID, NS_IFOCUSTRACKER_IID); +static NS_DEFINE_IID(kIDomSelectionListenerIID, NS_IDOMSELECTIONLISTENER_IID); static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID); static NS_DEFINE_IID(kICaretIID, NS_ICARET_IID); static NS_DEFINE_IID(kICaretID, NS_ICARET_IID); @@ -181,8 +184,8 @@ static NS_DEFINE_IID(kIContentIID, NS_ICONTENT_IID); static NS_DEFINE_IID(kIScrollableViewIID, NS_ISCROLLABLEVIEW_IID); class PresShell : public nsIPresShell, public nsIViewObserver, - private nsIDocumentObserver, public nsIFocusTracker - + private nsIDocumentObserver, public nsIFocusTracker, + public nsIDOMSelectionListener { public: PresShell(); @@ -310,6 +313,8 @@ public: NS_IMETHOD GetCaret(nsICaret **outCaret); NS_IMETHOD RefreshCaret(); + // nsIDOMSelectionListener interface + NS_IMETHOD NotifySelectionChanged(); // implementation void HandleCantRenderReplacedElementEvent(nsIFrame* aFrame); @@ -467,6 +472,12 @@ PresShell::QueryInterface(const nsIID& aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(kIDomSelectionListenerIID)) { + nsIDOMSelectionListener* tmp = this; + *aInstancePtr = (void*) tmp; + NS_ADDREF_THIS(); + return NS_OK; + } if (aIID.Equals(kISupportsIID)) { nsIPresShell* tmp = this; nsISupports* tmp2 = tmp; @@ -543,7 +554,7 @@ PresShell::Init(nsIDocument* aDocument, getter_AddRefs(mSelection)); if (!NS_SUCCEEDED(result)) return result; - + domselection->AddSelectionListener(this);//possible circular reference // XXX This code causes the document object (and the entire content model) to be leaked... #if 0 nsCOMPtrrange; @@ -766,6 +777,16 @@ PresShell::EndObservingDocument() if (nsnull != mDocument) { mDocument->RemoveObserver(this); } + if (mSelection){ + nsCOMPtr domselection; + nsresult result; + domselection = do_QueryInterface(mSelection , &result); + if (NS_FAILED(result)) + return result; + if (!domselection) + return NS_ERROR_UNEXPECTED; + domselection->RemoveSelectionListener(this); + } return NS_OK; } @@ -939,6 +960,17 @@ NS_IMETHODIMP PresShell::RefreshCaret() return NS_OK; } +/*implementation of the nsIDOMSelectionListener + it will invoke the resetselection to update the presentation shell's frames +*/ +NS_IMETHODIMP PresShell::NotifySelectionChanged() +{ + if (!mSelection) + return NS_ERROR_NULL_POINTER; + mSelection->ResetSelection(this, mRootFrame); + return NS_ERROR_NULL_POINTER; +} + nsresult PresShell::DisableCaret() { if (mCaret) @@ -1757,7 +1789,10 @@ PresShell::HandleEvent(nsIView *aView, if (nsnull != frame) { if (mSelection && mFocusEventFrame && aEvent->eventStructType == NS_KEY_EVENT) { + mSelection->EnableFrameNotification(PR_FALSE); mSelection->HandleKeyEvent((nsIFocusTracker *)this, aEvent, mFocusEventFrame); + mSelection->EnableFrameNotification(PR_TRUE); //prevents secondary reset selection called since + //we are a listener now. } frame->GetFrameForPoint(aEvent->point, &mCurrentEventFrame); if (nsnull != mCurrentEventFrame) { diff --git a/layout/html/base/src/nsTextFrame.cpp b/layout/html/base/src/nsTextFrame.cpp index 8ea73f0c363d..862a892a2f9b 100644 --- a/layout/html/base/src/nsTextFrame.cpp +++ b/layout/html/base/src/nsTextFrame.cpp @@ -870,8 +870,7 @@ TextFrame::PaintUnicodeText(nsIPresContext& aPresContext, CURSOR_COLOR); #endif } - else - { + else { nscoord x = dx; if (selectionOffset) { @@ -1142,7 +1141,6 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, shell->GetDocument(getter_AddRefs(doc)); PRBool displaySelection; displaySelection = doc->GetDisplaySelection(); - displaySelection = PR_FALSE; // Make enough space to transform PRUnichar wordBufMem[WORD_BUF_SIZE]; @@ -1151,7 +1149,7 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, PRInt32* ip = indicies; PRUnichar* paintBuf = paintBufMem; if (mContentLength > TEXT_BUF_SIZE) { - ip = new PRInt32[mContentLength]; + ip = new PRInt32[mContentLength+1]; paintBuf = new PRUnichar[mContentLength]; } nscoord width = mRect.width; @@ -1162,6 +1160,7 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, aTextStyle.mNumSpaces = PrepareUnicodeText(tx, displaySelection ? ip : nsnull, paintBuf, textLength, width); + ip[mContentLength] = ip[mContentLength-1]+1; //must set up last one for selection beyond edge if (mRect.width > mComputedWidth) { if (0 != aTextStyle.mNumSpaces) { nscoord extra = mRect.width - mComputedWidth; @@ -1182,18 +1181,33 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, PRUnichar* text = paintBuf; if (0 != textLength) { - if (!displaySelection) { + if (!displaySelection || !mSelected || mSelectionOffset > mContentLength) { // When there is no selection showing, use the fastest and // simplest rendering approach RenderString(aRenderingContext, aStyleContext, aTextStyle, text, textLength, dx, dy, width); } else { - SelectionInfo si; -// ComputeSelectionInfo(aRenderingContext, doc, ip, textLength, si); - nscoord textWidth; - if (si.mEmptySelection) { + if (mSelectionOffset < 0) + mSelectionOffset = 0; + if (mSelectionEnd < 0) + mSelectionEnd = mContentLength; + if (mSelectionEnd > mContentLength) + mSelectionEnd = mContentLength; + if (mSelectionOffset > mContentLength) + mSelectionOffset = mContentLength; + PRInt32 selectionEnd = mSelectionEnd; + PRInt32 selectionOffset = mSelectionOffset; + if (mSelectionEnd < mSelectionOffset) + { + selectionEnd = mSelectionOffset; + selectionOffset = mSelectionEnd; + } + //where are the selection points "really" + selectionOffset = ip[selectionOffset] - mContentOffset; + selectionEnd = ip[selectionEnd] - mContentOffset; + if (selectionOffset == selectionEnd){ RenderString(aRenderingContext, aStyleContext, aTextStyle, text, textLength, dx, dy, width); @@ -1202,7 +1216,7 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, #ifdef SHOW_SELECTION_CURSOR GetWidth(aRenderingContext, aTextStyle, - text, PRUint32(si.mStartOffset), textWidth); + text, PRUint32(selectionOffset), textWidth); RenderSelectionCursor(aRenderingContext, dx + textWidth, dy, mRect.height, CURSOR_COLOR); @@ -1211,21 +1225,21 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, else { nscoord x = dx; - if (0 != si.mStartOffset) { + if (selectionOffset) { // Render first (unselected) section GetWidth(aRenderingContext, aTextStyle, - text, PRUint32(si.mStartOffset), + text, PRUint32(selectionOffset), textWidth); RenderString(aRenderingContext, aStyleContext, aTextStyle, - text, si.mStartOffset, + text, selectionOffset, x, dy, textWidth); x += textWidth; } - PRInt32 secondLen = si.mEndOffset - si.mStartOffset; + PRInt32 secondLen = selectionEnd - selectionOffset; if (0 != secondLen) { // Get the width of the second (selected) section GetWidth(aRenderingContext, aTextStyle, - text + si.mStartOffset, + text + selectionOffset, PRUint32(secondLen), textWidth); // Render second (selected) section @@ -1233,21 +1247,24 @@ TextFrame::PaintTextSlowly(nsIPresContext& aPresContext, aRenderingContext.FillRect(x, dy, textWidth, mRect.height); aRenderingContext.SetColor(aTextStyle.mSelectionTextColor); RenderString(aRenderingContext, aStyleContext, aTextStyle, - text + si.mStartOffset, secondLen, + text + selectionOffset, secondLen, x, dy, textWidth); aRenderingContext.SetColor(aTextStyle.mColor->mColor); x += textWidth; } - if (textLength != si.mEndOffset) { - PRInt32 thirdLen = textLength - si.mEndOffset; + if (textLength != selectionEnd) { + PRInt32 thirdLen = textLength - selectionEnd; // Render third (unselected) section - GetWidth(aRenderingContext, aTextStyle, - text + si.mEndOffset, PRUint32(thirdLen), - textWidth); - RenderString(aRenderingContext, aStyleContext, aTextStyle, - text + si.mEndOffset, - thirdLen, x, dy, textWidth); + if (thirdLen > 0) //Text length is not negative or zero + { + GetWidth(aRenderingContext, aTextStyle, + text + selectionOffset, PRUint32(thirdLen), + textWidth); + RenderString(aRenderingContext, aStyleContext, aTextStyle, + text + selectionEnd, + thirdLen, x, dy, textWidth); + } } } } @@ -1298,7 +1315,6 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, displaySelection ? ip : nsnull, rawPaintBuf, textLength, width); ip[mContentLength] = ip[mContentLength-1]+1; //must set up last one for selection beyond edge - // Translate unicode data into ascii for rendering char* dst = paintBuf; char* end = dst + textLength; @@ -1347,9 +1363,10 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, // aRenderingContext.GetWidth(text, PRUint32(si.mStartOffset), textWidth); shell->RefreshCaret(); - + #ifdef SHOW_SELECTION_CURSOR aRenderingContext.GetWidth(text, PRUint32(selectionOffset), textWidth); + RenderSelectionCursor(aRenderingContext, dx + textWidth, dy, mRect.height, CURSOR_COLOR); @@ -1389,13 +1406,17 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, if (textLength != selectionEnd) { PRInt32 thirdLen = textLength - selectionEnd; - // Render third (unselected) section - aRenderingContext.GetWidth(text + selectionEnd, PRUint32(thirdLen), - textWidth); - aRenderingContext.DrawString(text + selectionEnd, - PRUint32(thirdLen), x, dy); - PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle, - x, dy, textWidth); + if (thirdLen > 0) //Text length is not negative or zero + { + + // Render third (unselected) section + aRenderingContext.GetWidth(text + selectionEnd, PRUint32(thirdLen), + textWidth); + aRenderingContext.DrawString(text + selectionEnd, + PRUint32(thirdLen), x, dy); + PaintTextDecorations(aRenderingContext, aStyleContext, aTextStyle, + x, dy, textWidth); + } } } }