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); + } } } }