Partial fix for bug 141900 (Text entry fields in forms excruciatingly slow.)

mozilla/content/base/public/nsISelectionController.idl
  mozilla/content/base/src/nsSelection.cpp
  mozilla/editor/composer/src/nsEditorShell.cpp
  mozilla/editor/idl/nsIPlaintextEditor.idl
  mozilla/editor/libeditor/base/nsEditor.cpp
  mozilla/editor/libeditor/base/nsEditor.h
  mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp
  mozilla/editor/libeditor/html/nsHTMLEditor.cpp
  mozilla/editor/libeditor/text/nsEditorEventListeners.cpp
  mozilla/editor/libeditor/text/nsPlaintextDataTransfer.cpp
  mozilla/editor/libeditor/text/nsPlaintextEditor.cpp
  mozilla/editor/txtsvc/src/nsTextServicesDocument.cpp
  mozilla/editor/ui/dialogs/content/EdTableProps.js
  mozilla/embedding/components/find/src/nsWebBrowserFind.cpp
  mozilla/extensions/xmlterm/base/mozXMLTermSession.cpp
  mozilla/layout/base/public/nsIFrameSelection.h
  mozilla/layout/html/base/src/nsPresShell.cpp
  mozilla/layout/html/forms/src/nsGfxTextControlFrame2.cpp
  mozilla/mailnews/compose/src/nsMsgCompose.cpp
  mozilla/xpfe/browser/resources/content/viewPartialSource.js

    - Added aIsSynchronous arg to the ScrollSelectionIntoView()
      method of nsISelectionController and nsIFrameSelection.
      Updated all callers to pass new arg.

    - Modified selection to post a plevent to call which does the
      call to ScrollIntoView() in the async ScrollIntoView() case.

    - Edits in text widgets now use asynchronous reflow, paint,
      and scroll processing full time.

    - Removed redundant ScrollSelectionIntoView() calls in the
      editor event listeners.

    - Editor IME code now forced to flush reflows and paints before
      getting caret coordinates.

r=jfrancis@netscape.com  sr=waterson@netscape.com
This commit is contained in:
kin%netscape.com 2002-06-13 20:43:32 +00:00
Родитель 2cc8934aad
Коммит 8996b9ec1c
3 изменённых файлов: 210 добавлений и 11 удалений

Просмотреть файл

@ -83,8 +83,11 @@ interface nsISelectionController : nsISelectionDisplay
*
* @param aType the selection to scroll into view. //SelectionType
* @param aRegion the region inside the selection to scroll into view. //SelectionRegion
* @param aIsSynchronous when true, scrolls the selection into view
* before returning. If false, posts a request which is processed
* at some point after the method returns.
*/
void scrollSelectionIntoView(in short type, in short region);
void scrollSelectionIntoView(in short type, in short region, in boolean isSynchronous);
/**
* RepaintSelection repaints the selection specified by aType.
*

Просмотреть файл

@ -98,6 +98,8 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
#include "nsITimerCallback.h"
#include "nsIServiceManager.h"
#include "nsIAutoCopy.h"
#include "nsIEventQueue.h"
#include "nsIEventQueueService.h"
//nodtifications
#include "nsIDOMDocument.h"
@ -138,6 +140,7 @@ static NS_DEFINE_IID(kCSubtreeIteratorCID, NS_SUBTREEITERATOR_CID);
class nsSelectionIterator;
class nsSelection;
class nsAutoScrollTimer;
struct nsScrollSelectionIntoViewEvent;
PRBool IsValidSelectionPoint(nsSelection *aFrameSel, nsIContent *aContent);
PRBool IsValidSelectionPoint(nsSelection *aFrameSel, nsIDOMNode *aDomNode);
@ -223,7 +226,8 @@ public:
nsresult GetSelectionRegionRectAndScrollableView(SelectionRegion aRegion, nsRect *aRect, nsIScrollableView **aScrollableView);
nsresult ScrollRectIntoView(nsIScrollableView *aScrollableView, nsRect& aRect, PRIntn aVPercent, PRIntn aHPercent, PRBool aScrollParentViews);
NS_IMETHOD ScrollIntoView(SelectionRegion aRegion=nsISelectionController::SELECTION_FOCUS_REGION);
nsresult PostScrollSelectionIntoViewEvent(SelectionRegion aRegion);
NS_IMETHOD ScrollIntoView(SelectionRegion aRegion=nsISelectionController::SELECTION_FOCUS_REGION, PRBool aIsSynchronous=PR_TRUE);
nsresult AddItem(nsIDOMRange *aRange);
nsresult RemoveItem(nsIDOMRange *aRange);
@ -277,6 +281,7 @@ public:
private:
friend class nsSelectionIterator;
friend struct nsScrollSelectionIntoViewEvent;
void setAnchorFocusRange(PRInt32 aIndex); //pass in index into FrameSelection
@ -304,6 +309,8 @@ private:
#ifdef IBMBIDI
PRBool mTrueDirection;
#endif
nsCOMPtr<nsIEventQueue> mEventQueue;
PRBool mScrollEventPosted;
};
// Stack-class to turn on/off selection batching for table selection
@ -354,7 +361,7 @@ public:
NS_IMETHOD ClearTableCellSelection(){mSelectingTableCellMode = 0; return NS_OK;}
NS_IMETHOD GetSelection(SelectionType aType, nsISelection **aDomSelection);
NS_IMETHOD ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion);
NS_IMETHOD ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion, PRBool aIsSynchronous);
NS_IMETHOD RepaintSelection(nsIPresContext* aPresContext, SelectionType aType);
NS_IMETHOD GetFrameForNodeOffset(nsIContent *aNode, PRInt32 aOffset, HINT aHint, nsIFrame **aReturnFrame, PRInt32 *aReturnOffset);
@ -2931,7 +2938,7 @@ nsSelection::GetSelection(SelectionType aType, nsISelection **aDomSelection)
}
NS_IMETHODIMP
nsSelection::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion)
nsSelection::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion, PRBool aIsSynchronous)
{
PRInt8 index = GetIndexFromSelectionType(aType);
if (index < 0)
@ -2940,7 +2947,7 @@ nsSelection::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegio
if (!mDomSelections[index])
return NS_ERROR_NULL_POINTER;
return mDomSelections[index]->ScrollIntoView(aRegion);
return mDomSelections[index]->ScrollIntoView(aRegion, aIsSynchronous);
}
NS_IMETHODIMP
@ -4488,6 +4495,7 @@ nsTypedSelection::nsTypedSelection(nsSelection *aList)
mAutoScrollTimer = nsnull;
NS_NewISupportsArray(getter_AddRefs(mSelectionListeners));
NS_INIT_REFCNT();
mScrollEventPosted = PR_FALSE;
}
@ -4500,6 +4508,7 @@ nsTypedSelection::nsTypedSelection()
mAutoScrollTimer = nsnull;
NS_NewISupportsArray(getter_AddRefs(mSelectionListeners));
NS_INIT_REFCNT();
mScrollEventPosted = PR_FALSE;
}
@ -4512,6 +4521,11 @@ nsTypedSelection::~nsTypedSelection()
mAutoScrollTimer->Stop();
NS_RELEASE(mAutoScrollTimer);
}
if (mEventQueue && mScrollEventPosted) {
mEventQueue->RevokeEvents(this);
mScrollEventPosted = PR_FALSE;
}
}
@ -7548,8 +7562,89 @@ nsTypedSelection::ScrollRectIntoView(nsIScrollableView *aScrollableView,
return rv;
}
static void PR_CALLBACK HandlePLEvent(nsScrollSelectionIntoViewEvent* aEvent);
static void PR_CALLBACK DestroyPLEvent(nsScrollSelectionIntoViewEvent* aEvent);
struct nsScrollSelectionIntoViewEvent : public PLEvent {
nsScrollSelectionIntoViewEvent(nsTypedSelection *aTypedSelection, SelectionRegion aRegion) {
if (!aTypedSelection)
return;
mTypedSelection = aTypedSelection;
mRegion = aRegion;
PL_InitEvent(this, aTypedSelection,
(PLHandleEventProc) ::HandlePLEvent,
(PLDestroyEventProc) ::DestroyPLEvent);
}
~nsScrollSelectionIntoViewEvent() {}
void HandleEvent() {
mTypedSelection->mScrollEventPosted = PR_FALSE;
if (!mTypedSelection)
return;
mTypedSelection->ScrollIntoView(mRegion, PR_TRUE);
}
nsTypedSelection *mTypedSelection;
SelectionRegion mRegion;
};
static void PR_CALLBACK HandlePLEvent(nsScrollSelectionIntoViewEvent* aEvent)
{
NS_ASSERTION(nsnull != aEvent,"Event is null");
aEvent->HandleEvent();
}
static void PR_CALLBACK DestroyPLEvent(nsScrollSelectionIntoViewEvent* aEvent)
{
NS_ASSERTION(nsnull != aEvent,"Event is null");
delete aEvent;
}
nsresult
nsTypedSelection::PostScrollSelectionIntoViewEvent(SelectionRegion aRegion)
{
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
if (!mEventQueue) {
nsresult rv;
// Cache the event queue of the current UI thread
nsCOMPtr<nsIEventQueueService> eventService = do_GetService(kEventQueueServiceCID, &rv);
if (NS_SUCCEEDED(rv) && (nsnull != eventService)) { // XXX this implies that the UI is the current thread.
rv = eventService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
}
}
if (mEventQueue) {
if (mScrollEventPosted) {
// We've already posted an event, revoke it and
// place a new one at the end of the queue to make
// sure that any new pending reflow events are processed
// before we scroll. This will insure that we scroll
// to the correct place on screen.
mEventQueue->RevokeEvents(this);
mScrollEventPosted = PR_FALSE;
}
nsScrollSelectionIntoViewEvent *ev = new nsScrollSelectionIntoViewEvent(this, aRegion);
if (ev) {
mEventQueue->PostEvent(ev);
mScrollEventPosted = PR_TRUE;
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsTypedSelection::ScrollIntoView(SelectionRegion aRegion)
nsTypedSelection::ScrollIntoView(SelectionRegion aRegion, PRBool aIsSynchronous)
{
nsresult result;
if (!mFrameSelection)
@ -7558,6 +7653,9 @@ nsTypedSelection::ScrollIntoView(SelectionRegion aRegion)
if (mFrameSelection->GetBatching())
return NS_OK;
if (!aIsSynchronous)
return PostScrollSelectionIntoViewEvent(aRegion);
//
// Shut the caret off before scrolling to avoid
// leaving caret turds on the screen!

Просмотреть файл

@ -98,6 +98,8 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
#include "nsITimerCallback.h"
#include "nsIServiceManager.h"
#include "nsIAutoCopy.h"
#include "nsIEventQueue.h"
#include "nsIEventQueueService.h"
//nodtifications
#include "nsIDOMDocument.h"
@ -138,6 +140,7 @@ static NS_DEFINE_IID(kCSubtreeIteratorCID, NS_SUBTREEITERATOR_CID);
class nsSelectionIterator;
class nsSelection;
class nsAutoScrollTimer;
struct nsScrollSelectionIntoViewEvent;
PRBool IsValidSelectionPoint(nsSelection *aFrameSel, nsIContent *aContent);
PRBool IsValidSelectionPoint(nsSelection *aFrameSel, nsIDOMNode *aDomNode);
@ -223,7 +226,8 @@ public:
nsresult GetSelectionRegionRectAndScrollableView(SelectionRegion aRegion, nsRect *aRect, nsIScrollableView **aScrollableView);
nsresult ScrollRectIntoView(nsIScrollableView *aScrollableView, nsRect& aRect, PRIntn aVPercent, PRIntn aHPercent, PRBool aScrollParentViews);
NS_IMETHOD ScrollIntoView(SelectionRegion aRegion=nsISelectionController::SELECTION_FOCUS_REGION);
nsresult PostScrollSelectionIntoViewEvent(SelectionRegion aRegion);
NS_IMETHOD ScrollIntoView(SelectionRegion aRegion=nsISelectionController::SELECTION_FOCUS_REGION, PRBool aIsSynchronous=PR_TRUE);
nsresult AddItem(nsIDOMRange *aRange);
nsresult RemoveItem(nsIDOMRange *aRange);
@ -277,6 +281,7 @@ public:
private:
friend class nsSelectionIterator;
friend struct nsScrollSelectionIntoViewEvent;
void setAnchorFocusRange(PRInt32 aIndex); //pass in index into FrameSelection
@ -304,6 +309,8 @@ private:
#ifdef IBMBIDI
PRBool mTrueDirection;
#endif
nsCOMPtr<nsIEventQueue> mEventQueue;
PRBool mScrollEventPosted;
};
// Stack-class to turn on/off selection batching for table selection
@ -354,7 +361,7 @@ public:
NS_IMETHOD ClearTableCellSelection(){mSelectingTableCellMode = 0; return NS_OK;}
NS_IMETHOD GetSelection(SelectionType aType, nsISelection **aDomSelection);
NS_IMETHOD ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion);
NS_IMETHOD ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion, PRBool aIsSynchronous);
NS_IMETHOD RepaintSelection(nsIPresContext* aPresContext, SelectionType aType);
NS_IMETHOD GetFrameForNodeOffset(nsIContent *aNode, PRInt32 aOffset, HINT aHint, nsIFrame **aReturnFrame, PRInt32 *aReturnOffset);
@ -2931,7 +2938,7 @@ nsSelection::GetSelection(SelectionType aType, nsISelection **aDomSelection)
}
NS_IMETHODIMP
nsSelection::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion)
nsSelection::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion, PRBool aIsSynchronous)
{
PRInt8 index = GetIndexFromSelectionType(aType);
if (index < 0)
@ -2940,7 +2947,7 @@ nsSelection::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegio
if (!mDomSelections[index])
return NS_ERROR_NULL_POINTER;
return mDomSelections[index]->ScrollIntoView(aRegion);
return mDomSelections[index]->ScrollIntoView(aRegion, aIsSynchronous);
}
NS_IMETHODIMP
@ -4488,6 +4495,7 @@ nsTypedSelection::nsTypedSelection(nsSelection *aList)
mAutoScrollTimer = nsnull;
NS_NewISupportsArray(getter_AddRefs(mSelectionListeners));
NS_INIT_REFCNT();
mScrollEventPosted = PR_FALSE;
}
@ -4500,6 +4508,7 @@ nsTypedSelection::nsTypedSelection()
mAutoScrollTimer = nsnull;
NS_NewISupportsArray(getter_AddRefs(mSelectionListeners));
NS_INIT_REFCNT();
mScrollEventPosted = PR_FALSE;
}
@ -4512,6 +4521,11 @@ nsTypedSelection::~nsTypedSelection()
mAutoScrollTimer->Stop();
NS_RELEASE(mAutoScrollTimer);
}
if (mEventQueue && mScrollEventPosted) {
mEventQueue->RevokeEvents(this);
mScrollEventPosted = PR_FALSE;
}
}
@ -7548,8 +7562,89 @@ nsTypedSelection::ScrollRectIntoView(nsIScrollableView *aScrollableView,
return rv;
}
static void PR_CALLBACK HandlePLEvent(nsScrollSelectionIntoViewEvent* aEvent);
static void PR_CALLBACK DestroyPLEvent(nsScrollSelectionIntoViewEvent* aEvent);
struct nsScrollSelectionIntoViewEvent : public PLEvent {
nsScrollSelectionIntoViewEvent(nsTypedSelection *aTypedSelection, SelectionRegion aRegion) {
if (!aTypedSelection)
return;
mTypedSelection = aTypedSelection;
mRegion = aRegion;
PL_InitEvent(this, aTypedSelection,
(PLHandleEventProc) ::HandlePLEvent,
(PLDestroyEventProc) ::DestroyPLEvent);
}
~nsScrollSelectionIntoViewEvent() {}
void HandleEvent() {
mTypedSelection->mScrollEventPosted = PR_FALSE;
if (!mTypedSelection)
return;
mTypedSelection->ScrollIntoView(mRegion, PR_TRUE);
}
nsTypedSelection *mTypedSelection;
SelectionRegion mRegion;
};
static void PR_CALLBACK HandlePLEvent(nsScrollSelectionIntoViewEvent* aEvent)
{
NS_ASSERTION(nsnull != aEvent,"Event is null");
aEvent->HandleEvent();
}
static void PR_CALLBACK DestroyPLEvent(nsScrollSelectionIntoViewEvent* aEvent)
{
NS_ASSERTION(nsnull != aEvent,"Event is null");
delete aEvent;
}
nsresult
nsTypedSelection::PostScrollSelectionIntoViewEvent(SelectionRegion aRegion)
{
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
if (!mEventQueue) {
nsresult rv;
// Cache the event queue of the current UI thread
nsCOMPtr<nsIEventQueueService> eventService = do_GetService(kEventQueueServiceCID, &rv);
if (NS_SUCCEEDED(rv) && (nsnull != eventService)) { // XXX this implies that the UI is the current thread.
rv = eventService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue));
}
}
if (mEventQueue) {
if (mScrollEventPosted) {
// We've already posted an event, revoke it and
// place a new one at the end of the queue to make
// sure that any new pending reflow events are processed
// before we scroll. This will insure that we scroll
// to the correct place on screen.
mEventQueue->RevokeEvents(this);
mScrollEventPosted = PR_FALSE;
}
nsScrollSelectionIntoViewEvent *ev = new nsScrollSelectionIntoViewEvent(this, aRegion);
if (ev) {
mEventQueue->PostEvent(ev);
mScrollEventPosted = PR_TRUE;
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsTypedSelection::ScrollIntoView(SelectionRegion aRegion)
nsTypedSelection::ScrollIntoView(SelectionRegion aRegion, PRBool aIsSynchronous)
{
nsresult result;
if (!mFrameSelection)
@ -7558,6 +7653,9 @@ nsTypedSelection::ScrollIntoView(SelectionRegion aRegion)
if (mFrameSelection->GetBatching())
return NS_OK;
if (!aIsSynchronous)
return PostScrollSelectionIntoViewEvent(aRegion);
//
// Shut the caret off before scrolling to avoid
// leaving caret turds on the screen!