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)

This commit is contained in:
mjudge%netscape.com 1999-02-19 23:47:36 +00:00
parent a7658c739f
commit fb3a597e8a
13 changed files with 357 additions and 146 deletions

View File

@ -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

View File

@ -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;
};

View File

@ -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
nsCOMPtr<nsIDOMRange>range;
@ -766,6 +777,16 @@ PresShell::EndObservingDocument()
if (nsnull != mDocument) {
mDocument->RemoveObserver(this);
}
if (mSelection){
nsCOMPtr<nsIDOMSelection> 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) {

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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

View File

@ -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<nsIDOMNode> mFocusNode; //where is the carret
PRInt32 mFocusOffset;
nsCOMPtr<nsISupportsArray> mSelectionListeners;
//batching
PRBool mBatching;
PRBool mChangesDuringBatching;
PRBool mNotifyFrames;
nsCOMPtr<nsISupportsArray> 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<nsIContent> content;
nsCOMPtr<nsIDOMNode> 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<nsIDOMRange> 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<nsISupports> thisEntry(dont_QueryInterface(mSelectionListeners->ElementAt(i)));
nsCOMPtr<nsIDOMSelectionListener> thisListener(do_QueryInterface(thisEntry));
nsCOMPtr<nsIDOMSelectionListener> 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<nsIDOMRange> 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();
}

View File

@ -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);

View File

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

View File

@ -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);

View File

@ -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
nsCOMPtr<nsIDOMRange>range;
@ -766,6 +777,16 @@ PresShell::EndObservingDocument()
if (nsnull != mDocument) {
mDocument->RemoveObserver(this);
}
if (mSelection){
nsCOMPtr<nsIDOMSelection> 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) {

View File

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