зеркало из https://github.com/mozilla/gecko-dev.git
Make sure to process style updates before reflow, and both before painting. Bug 375436, r+sr=roc, a=dbaron
This commit is contained in:
Родитель
65276cb588
Коммит
e51e8403e6
|
@ -42,21 +42,14 @@
|
|||
* decide what to flush.
|
||||
*/
|
||||
enum mozFlushType {
|
||||
Flush_Content = 0x1, /* flush the content model construction */
|
||||
Flush_SinkNotifications = 0x2, /* flush the frame model construction */
|
||||
Flush_StyleReresolves = 0x4, /* flush style reresolution */
|
||||
Flush_OnlyReflow = 0x8, /* flush reflows */
|
||||
Flush_OnlyPaint = 0x10, /* flush painting */
|
||||
Flush_ContentAndNotify = (Flush_Content | Flush_SinkNotifications),
|
||||
Flush_Frames = (Flush_Content | Flush_SinkNotifications |
|
||||
Flush_StyleReresolves),
|
||||
Flush_Style = (Flush_Content | Flush_SinkNotifications |
|
||||
Flush_StyleReresolves),
|
||||
Flush_Layout = (Flush_Content | Flush_SinkNotifications |
|
||||
Flush_StyleReresolves | Flush_OnlyReflow),
|
||||
Flush_Display = (Flush_Content | Flush_SinkNotifications |
|
||||
Flush_StyleReresolves | Flush_OnlyReflow |
|
||||
Flush_OnlyPaint)
|
||||
Flush_Content = 1, /* flush the content model construction */
|
||||
Flush_ContentAndNotify = 2, /* As above, plus flush the frame model
|
||||
construction and other nsIMutationObserver
|
||||
notifications. */
|
||||
Flush_Style = 3, /* As above, plus flush style reresolution */
|
||||
Flush_Frames = Flush_Style,
|
||||
Flush_Layout = 4, /* As above, plus flush reflow */
|
||||
Flush_Display = 5 /* As above, plus flush painting */
|
||||
};
|
||||
|
||||
#endif /* mozFlushType_h___ */
|
||||
|
|
|
@ -4786,8 +4786,7 @@ nsDocument::FlushPendingNotifications(mozFlushType aType)
|
|||
{
|
||||
// Determine if it is safe to flush the sink notifications
|
||||
// by determining if it safe to flush all the presshells.
|
||||
if ((aType & Flush_Content) && mParser &&
|
||||
(!(aType & Flush_SinkNotifications) || IsSafeToFlush())) {
|
||||
if (mParser && (aType == Flush_Content || IsSafeToFlush())) {
|
||||
nsCOMPtr<nsIContentSink> sink = mParser->GetContentSink();
|
||||
if (sink) {
|
||||
sink->FlushPendingNotifications(aType);
|
||||
|
@ -4798,8 +4797,7 @@ nsDocument::FlushPendingNotifications(mozFlushType aType)
|
|||
|
||||
nsPIDOMWindow *window = GetWindow();
|
||||
|
||||
if (aType == (aType & (Flush_Content | Flush_SinkNotifications)) ||
|
||||
!window) {
|
||||
if (aType <= Flush_ContentAndNotify || !window) {
|
||||
// Nothing to do here
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3199,13 +3199,13 @@ HTMLContentSink::FlushPendingNotifications(mozFlushType aType)
|
|||
// Only flush tags if we're not doing the notification ourselves
|
||||
// (since we aren't reentrant)
|
||||
if (mCurrentContext && !mInNotification) {
|
||||
if (aType & Flush_SinkNotifications) {
|
||||
if (aType >= Flush_ContentAndNotify) {
|
||||
mCurrentContext->FlushTags();
|
||||
}
|
||||
else {
|
||||
mCurrentContext->FlushText();
|
||||
}
|
||||
if (aType & Flush_OnlyReflow) {
|
||||
if (aType >= Flush_Layout) {
|
||||
// Make sure that layout has started so that the reflow flush
|
||||
// will actually happen.
|
||||
StartLayout(PR_TRUE);
|
||||
|
|
|
@ -1579,13 +1579,13 @@ nsXMLContentSink::FlushPendingNotifications(mozFlushType aType)
|
|||
// Only flush tags if we're not doing the notification ourselves
|
||||
// (since we aren't reentrant)
|
||||
if (!mInNotification) {
|
||||
if (aType & Flush_SinkNotifications) {
|
||||
if (aType >= Flush_ContentAndNotify) {
|
||||
FlushTags();
|
||||
}
|
||||
else {
|
||||
FlushText();
|
||||
}
|
||||
if (aType & Flush_OnlyReflow) {
|
||||
if (aType >= Flush_Layout) {
|
||||
// Make sure that layout has started so that the reflow flush
|
||||
// will actually happen.
|
||||
MaybeStartLayout(PR_TRUE);
|
||||
|
|
|
@ -1099,6 +1099,11 @@ protected:
|
|||
// Utility method to restore the root scrollframe state
|
||||
void RestoreRootScrollPosition();
|
||||
|
||||
// Method to handle actually flushing. This allows the caller to control
|
||||
// whether the reflow flush (if any) should be interruptible.
|
||||
nsresult DoFlushPendingNotifications(mozFlushType aType,
|
||||
PRBool aInterruptibleReflow);
|
||||
|
||||
nsICSSStyleSheet* mPrefStyleSheet; // mStyleSet owns it but we maintain a ref, may be null
|
||||
#ifdef DEBUG
|
||||
PRUint32 mUpdateCount;
|
||||
|
@ -4369,9 +4374,14 @@ PresShell::IsSafeToFlush(PRBool& aIsSafeToFlush)
|
|||
NS_IMETHODIMP
|
||||
PresShell::FlushPendingNotifications(mozFlushType aType)
|
||||
{
|
||||
NS_ASSERTION(aType & (Flush_StyleReresolves | Flush_OnlyReflow |
|
||||
Flush_OnlyPaint),
|
||||
"Why did we get called?");
|
||||
return DoFlushPendingNotifications(aType, PR_FALSE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::DoFlushPendingNotifications(mozFlushType aType,
|
||||
PRBool aInterruptibleReflow)
|
||||
{
|
||||
NS_ASSERTION(aType >= Flush_Frames, "Why did we get called?");
|
||||
|
||||
PRBool isSafeToFlush;
|
||||
IsSafeToFlush(isSafeToFlush);
|
||||
|
@ -4391,22 +4401,20 @@ PresShell::FlushPendingNotifications(mozFlushType aType)
|
|||
// batching if we only have style reresolve
|
||||
viewManager->BeginUpdateViewBatch();
|
||||
|
||||
if (aType & Flush_StyleReresolves) {
|
||||
mFrameConstructor->ProcessPendingRestyles();
|
||||
}
|
||||
mFrameConstructor->ProcessPendingRestyles();
|
||||
|
||||
if (aType & Flush_OnlyReflow && !mIsDestroying) {
|
||||
if (aType >= Flush_Layout && !mIsDestroying) {
|
||||
mFrameConstructor->RecalcQuotesAndCounters();
|
||||
ProcessReflowCommands(PR_FALSE);
|
||||
ProcessReflowCommands(aInterruptibleReflow);
|
||||
}
|
||||
|
||||
PRUint32 updateFlags = NS_VMREFRESH_NO_SYNC;
|
||||
if (aType & Flush_OnlyPaint) {
|
||||
if (aType >= Flush_Display) {
|
||||
// Flushing paints, so perform the invalidates and drawing
|
||||
// immediately
|
||||
updateFlags = NS_VMREFRESH_IMMEDIATE;
|
||||
}
|
||||
else if (!(aType & Flush_OnlyReflow)) {
|
||||
else if (aType < Flush_Layout) {
|
||||
// Not flushing reflows, so do deferred invalidates. This will keep us
|
||||
// from possibly flushing out reflows due to invalidates being processed
|
||||
// at the end of this view batch.
|
||||
|
@ -5786,12 +5794,7 @@ PresShell::WillPaint()
|
|||
// reflow being interspersed. Note that we _do_ allow this to be
|
||||
// interruptible; if we can't do all the reflows it's better to flicker a bit
|
||||
// than to freeze up.
|
||||
// XXXbz this update batch may not be strictly necessary, but it's good form.
|
||||
// XXXbz should we be flushing out style changes here? Probably not, I'd say.
|
||||
NS_ASSERTION(mViewManager, "Something weird is going on");
|
||||
mViewManager->BeginUpdateViewBatch();
|
||||
ProcessReflowCommands(PR_TRUE);
|
||||
mViewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
DoFlushPendingNotifications(Flush_Layout, PR_TRUE);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -5929,9 +5932,8 @@ PresShell::ReflowEvent::Run() {
|
|||
// Set a kung fu death grip on the view manager associated with the pres shell
|
||||
// before processing that pres shell's reflow commands. Fixes bug 54868.
|
||||
nsCOMPtr<nsIViewManager> viewManager = ps->GetViewManager();
|
||||
viewManager->BeginUpdateViewBatch();
|
||||
ps->ProcessReflowCommands(PR_TRUE);
|
||||
viewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
|
||||
|
||||
ps->DoFlushPendingNotifications(Flush_Layout, PR_TRUE);
|
||||
|
||||
// Now, explicitly release the pres shell before the view manager
|
||||
ps = nsnull;
|
||||
|
|
|
@ -418,10 +418,9 @@ nsComboboxControlFrame::ShowList(nsPresContext* aPresContext, PRBool aShowList)
|
|||
mListControlFrame->CaptureMouseEvents(PR_TRUE);
|
||||
}
|
||||
|
||||
// Don't flush anything but reflows lest it destroy us
|
||||
shell->GetDocument()->FlushPendingNotifications(Flush_OnlyReflow);
|
||||
// XXXbz so why do we need to flush here, exactly?
|
||||
shell->GetDocument()->FlushPendingNotifications(Flush_Layout);
|
||||
if (!weakFrame.IsAlive()) {
|
||||
NS_ERROR("Flush_OnlyReflow destroyed the frame");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -2738,15 +2738,6 @@ nsListControlFrame::KeyPress(nsIDOMEvent* aKeyEvent)
|
|||
}
|
||||
#endif
|
||||
|
||||
// XXX - Are we cover up a problem here???
|
||||
// Why aren't they getting flushed each time?
|
||||
// because this isn't needed for Gfx
|
||||
if (IsInDropDownMode()) {
|
||||
// Don't flush anything but reflows lest it destroy us
|
||||
PresContext()->PresShell()->
|
||||
GetDocument()->FlushPendingNotifications(Flush_OnlyReflow);
|
||||
}
|
||||
|
||||
// Make sure the SelectArea frame gets painted
|
||||
Invalidate(nsRect(0,0,mRect.width,mRect.height), PR_TRUE);
|
||||
|
||||
|
|
|
@ -1875,7 +1875,7 @@ nsGfxScrollFrameInner::AsyncScrollPortEvent::Run()
|
|||
{
|
||||
if (mInner) {
|
||||
mInner->mOuter->PresContext()->GetPresShell()->
|
||||
FlushPendingNotifications(Flush_OnlyReflow);
|
||||
FlushPendingNotifications(Flush_Layout);
|
||||
}
|
||||
return mInner ? mInner->FireScrollPortEvent() : NS_OK;
|
||||
}
|
||||
|
|
|
@ -212,7 +212,10 @@ public:
|
|||
nsresult ScrollRectIntoView(nsIScrollableView *aScrollableView, nsRect& aRect, PRIntn aVPercent, PRIntn aHPercent, PRBool aScrollParentViews);
|
||||
|
||||
nsresult PostScrollSelectionIntoViewEvent(SelectionRegion aRegion);
|
||||
NS_IMETHOD ScrollIntoView(SelectionRegion aRegion=nsISelectionController::SELECTION_FOCUS_REGION, PRBool aIsSynchronous=PR_TRUE);
|
||||
// aDoFlush only matters if aIsSynchronous is true. If not, we'll just flush
|
||||
// when the scroll event fires so we make sure to scroll to the right place.
|
||||
nsresult ScrollIntoView(SelectionRegion aRegion, PRBool aIsSynchronous,
|
||||
PRBool aDoFlush);
|
||||
nsresult AddItem(nsIDOMRange *aRange);
|
||||
nsresult RemoveItem(nsIDOMRange *aRange);
|
||||
nsresult Clear(nsPresContext* aPresContext);
|
||||
|
@ -1262,7 +1265,9 @@ nsFrameSelection::MoveCaret(PRUint32 aKeycode,
|
|||
}
|
||||
result = mDomSelections[index]->Collapse(weakNodeUsed, offsetused);
|
||||
mHint = HINTRIGHT;
|
||||
mDomSelections[index]->ScrollIntoView();
|
||||
mDomSelections[index]->
|
||||
ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION,
|
||||
PR_FALSE, PR_FALSE);
|
||||
return NS_OK;
|
||||
|
||||
case nsIDOMKeyEvent::DOM_VK_RIGHT :
|
||||
|
@ -1277,7 +1282,9 @@ nsFrameSelection::MoveCaret(PRUint32 aKeycode,
|
|||
}
|
||||
result = mDomSelections[index]->Collapse(weakNodeUsed, offsetused);
|
||||
mHint = HINTLEFT;
|
||||
mDomSelections[index]->ScrollIntoView();
|
||||
mDomSelections[index]->
|
||||
ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION,
|
||||
PR_FALSE, PR_FALSE);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -1426,7 +1433,9 @@ nsFrameSelection::MoveCaret(PRUint32 aKeycode,
|
|||
if (NS_SUCCEEDED(result))
|
||||
{
|
||||
mHint = tHint; //save the hint parameter now for the next time
|
||||
result = mDomSelections[index]->ScrollIntoView();
|
||||
result = mDomSelections[index]->
|
||||
ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION,
|
||||
PR_FALSE, PR_FALSE);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -2538,7 +2547,8 @@ nsFrameSelection::ScrollSelectionIntoView(SelectionType aType,
|
|||
if (!mDomSelections[index])
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
return mDomSelections[index]->ScrollIntoView(aRegion, aIsSynchronous);
|
||||
return mDomSelections[index]->ScrollIntoView(aRegion, aIsSynchronous,
|
||||
PR_FALSE);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -5831,7 +5841,8 @@ nsTypedSelection::RemoveRange(nsIDOMRange* aRange)
|
|||
if (cnt > 0)
|
||||
{
|
||||
setAnchorFocusRange(cnt - 1);//reset anchor to LAST range.
|
||||
ScrollIntoView();
|
||||
ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION, PR_FALSE,
|
||||
PR_FALSE);
|
||||
}
|
||||
}
|
||||
if (!mFrameSelection)
|
||||
|
@ -7251,7 +7262,7 @@ nsTypedSelection::ScrollSelectionIntoViewEvent::Run()
|
|||
return NS_OK; // event revoked
|
||||
|
||||
mTypedSelection->mScrollEvent.Forget();
|
||||
mTypedSelection->ScrollIntoView(mRegion, PR_TRUE);
|
||||
mTypedSelection->ScrollIntoView(mRegion, PR_TRUE, PR_TRUE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -7273,8 +7284,9 @@ nsTypedSelection::PostScrollSelectionIntoViewEvent(SelectionRegion aRegion)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTypedSelection::ScrollIntoView(SelectionRegion aRegion, PRBool aIsSynchronous)
|
||||
nsresult
|
||||
nsTypedSelection::ScrollIntoView(SelectionRegion aRegion,
|
||||
PRBool aIsSynchronous, PRBool aDoFlush)
|
||||
{
|
||||
nsresult result;
|
||||
if (!mFrameSelection)
|
||||
|
@ -7298,13 +7310,21 @@ nsTypedSelection::ScrollIntoView(SelectionRegion aRegion, PRBool aIsSynchronous)
|
|||
presShell->GetCaret(getter_AddRefs(caret));
|
||||
if (caret)
|
||||
{
|
||||
StCaretHider caretHider(caret); // stack-based class hides and shows the caret
|
||||
// Now that text frame character offsets are always valid (though not
|
||||
// necessarily correct), the worst that will happen if we don't flush here
|
||||
// is that some callers might scroll to the wrong place. Those should
|
||||
// either manually flush if they're in a safe position for it or use the
|
||||
// async version of this method.
|
||||
if (aDoFlush) {
|
||||
presShell->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
// We are going to scroll to a character offset within a frame by
|
||||
// using APIs on the scrollable view directly. So we need to
|
||||
// flush out pending reflows to make sure that frames are up-to-date.
|
||||
// We crash otherwise - bug 252970#c97
|
||||
presShell->FlushPendingNotifications(Flush_OnlyReflow);
|
||||
// Reget the presshell, since it might have gone away.
|
||||
result = GetPresShell(getter_AddRefs(presShell));
|
||||
if (NS_FAILED(result) || !presShell)
|
||||
return result;
|
||||
}
|
||||
|
||||
StCaretHider caretHider(caret); // stack-based class hides and shows the caret
|
||||
|
||||
//
|
||||
// Scroll the selection region into view.
|
||||
|
|
|
@ -1918,7 +1918,7 @@ nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
|
|||
NS_ASSERTION(aPO->mPresShell, "Presshell should still be here");
|
||||
|
||||
// Process the reflow event InitialReflow posted
|
||||
aPO->mPresShell->FlushPendingNotifications(Flush_OnlyReflow);
|
||||
aPO->mPresShell->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
nsCOMPtr<nsIPresShell> displayShell;
|
||||
aPO->mDocShell->GetPresShell(getter_AddRefs(displayShell));
|
||||
|
|
|
@ -122,7 +122,7 @@ nsInspectorCSSUtils::GetStyleContextForContent(nsIContent* aContent,
|
|||
nsIPresShell* aPresShell)
|
||||
{
|
||||
if (!aPseudo) {
|
||||
aPresShell->FlushPendingNotifications(Flush_StyleReresolves);
|
||||
aPresShell->FlushPendingNotifications(Flush_Style);
|
||||
nsIFrame* frame = aPresShell->GetPrimaryFrameFor(aContent);
|
||||
if (frame) {
|
||||
nsStyleContext* result = GetStyleContextForFrame(frame);
|
||||
|
|
|
@ -263,6 +263,11 @@ nsListBoxBodyFrame::Destroy()
|
|||
if (mReflowCallbackPosted)
|
||||
PresContext()->PresShell()->CancelReflowCallback(this);
|
||||
|
||||
// Revoke any pending position changed events
|
||||
for (PRUint32 i = 0; i < mPendingPositionChangeEvents.Length(); ++i) {
|
||||
mPendingPositionChangeEvents[i]->Revoke();
|
||||
}
|
||||
|
||||
// Make sure we tell our listbox's box object we're being destroyed.
|
||||
for (nsIFrame *a = mParent; a; a = a->GetParent()) {
|
||||
nsIContent *content = a->GetContent();
|
||||
|
@ -421,9 +426,6 @@ nsListBoxBodyFrame::PositionChanged(nsISupports* aScrollbar, PRInt32 aOldIndex,
|
|||
|
||||
smoother->Stop();
|
||||
|
||||
// Don't flush anything but reflows lest it destroy us
|
||||
mContent->GetDocument()->FlushPendingNotifications(Flush_OnlyReflow);
|
||||
|
||||
smoother->mDelta = newTwipIndex > oldTwipIndex ? rowDelta : -rowDelta;
|
||||
|
||||
smoother->Start();
|
||||
|
@ -568,7 +570,9 @@ nsListBoxBodyFrame::EnsureIndexIsVisible(PRInt32 aRowIndex)
|
|||
mCurrentIndex += delta;
|
||||
}
|
||||
|
||||
InternalPositionChanged(up, delta);
|
||||
// Safe to not go off an event here, since this is coming from the
|
||||
// box object.
|
||||
DoInternalPositionChangedSync(up, delta);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -595,6 +599,7 @@ nsListBoxBodyFrame::ScrollByLines(PRInt32 aNumLines)
|
|||
// we have to do a sync update for mac because if we scroll too quickly
|
||||
// w/out going back to the main event loop we can easily scroll the wrong
|
||||
// bits and it looks like garbage (bug 63465).
|
||||
// XXXbz is this seriously still needed?
|
||||
|
||||
// I'd use Composite here, but it doesn't always work.
|
||||
// vm->Composite();
|
||||
|
@ -844,17 +849,19 @@ nsListBoxBodyFrame::ScrollToIndex(PRInt32 aRowIndex)
|
|||
return NS_OK;
|
||||
|
||||
mCurrentIndex = newIndex;
|
||||
InternalPositionChanged(up, delta);
|
||||
|
||||
// Since we're going to flush anyway, we need to not do this off an event
|
||||
DoInternalPositionChangedSync(up, delta);
|
||||
|
||||
// This change has to happen immediately.
|
||||
// Flush any pending reflow commands.
|
||||
// Don't flush anything but reflows lest it destroy us
|
||||
mContent->GetDocument()->FlushPendingNotifications(Flush_OnlyReflow);
|
||||
// XXXbz why, exactly?
|
||||
mContent->GetDocument()->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsListBoxBodyFrame::InternalPositionChangedCallback()
|
||||
{
|
||||
nsListScrollSmoother* smoother = GetSmoother();
|
||||
|
@ -867,12 +874,49 @@ nsListBoxBodyFrame::InternalPositionChangedCallback()
|
|||
if (mCurrentIndex < 0)
|
||||
mCurrentIndex = 0;
|
||||
|
||||
return InternalPositionChanged(smoother->mDelta < 0, smoother->mDelta < 0 ? -smoother->mDelta : smoother->mDelta);
|
||||
return DoInternalPositionChangedSync(smoother->mDelta < 0,
|
||||
smoother->mDelta < 0 ?
|
||||
-smoother->mDelta : smoother->mDelta);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsListBoxBodyFrame::InternalPositionChanged(PRBool aUp, PRInt32 aDelta)
|
||||
{
|
||||
{
|
||||
nsRefPtr<nsPositionChangedEvent> ev =
|
||||
new nsPositionChangedEvent(this, aUp, aDelta);
|
||||
nsresult rv = NS_DispatchToCurrentThread(ev);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (!mPendingPositionChangeEvents.AppendElement(ev)) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
ev->Revoke();
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsListBoxBodyFrame::DoInternalPositionChangedSync(PRBool aUp, PRInt32 aDelta)
|
||||
{
|
||||
nsWeakFrame weak(this);
|
||||
|
||||
// Process all the pending position changes first
|
||||
nsTArray< nsRefPtr<nsPositionChangedEvent> > temp;
|
||||
temp.SwapElements(mPendingPositionChangeEvents);
|
||||
for (PRUint32 i = 0; i < temp.Length(); ++i) {
|
||||
temp[i]->Run();
|
||||
temp[i]->Revoke();
|
||||
}
|
||||
|
||||
if (!weak.IsAlive()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return DoInternalPositionChanged(aUp, aDelta);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsListBoxBodyFrame::DoInternalPositionChanged(PRBool aUp, PRInt32 aDelta)
|
||||
{
|
||||
if (aDelta == 0)
|
||||
return NS_OK;
|
||||
|
||||
|
@ -882,7 +926,11 @@ nsListBoxBodyFrame::InternalPositionChanged(PRBool aUp, PRInt32 aDelta)
|
|||
// begin timing how long it takes to scroll a row
|
||||
PRTime start = PR_Now();
|
||||
|
||||
mContent->GetDocument()->FlushPendingNotifications(Flush_OnlyReflow);
|
||||
nsWeakFrame weakThis(this);
|
||||
mContent->GetDocument()->FlushPendingNotifications(Flush_Layout);
|
||||
if (!weakThis.IsAlive()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRInt32 visibleRows = 0;
|
||||
if (mRowHeight)
|
||||
|
@ -922,7 +970,11 @@ nsListBoxBodyFrame::InternalPositionChanged(PRBool aUp, PRInt32 aDelta)
|
|||
FrameNeedsReflow(this, nsIPresShell::eResize, NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
// Flush calls CreateRows
|
||||
// XXXbz there has to be a better way to do this than flushing!
|
||||
presContext->PresShell()->FlushPendingNotifications(Flush_OnlyReflow);
|
||||
presContext->PresShell()->FlushPendingNotifications(Flush_Layout);
|
||||
if (!weakThis.IsAlive()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mScrolling = PR_FALSE;
|
||||
|
||||
VerticalScroll(mYPosition);
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "nsIReflowCallback.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsBoxLayoutState.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
class nsListScrollSmoother;
|
||||
nsIFrame* NS_NewListBoxBodyFrame(nsIPresShell* aPresShell,
|
||||
|
@ -105,8 +106,13 @@ public:
|
|||
nscoord ComputeIntrinsicWidth(nsBoxLayoutState& aBoxLayoutState);
|
||||
|
||||
// scrolling
|
||||
NS_IMETHOD InternalPositionChangedCallback();
|
||||
NS_IMETHOD InternalPositionChanged(PRBool aUp, PRInt32 aDelta);
|
||||
nsresult InternalPositionChangedCallback();
|
||||
nsresult InternalPositionChanged(PRBool aUp, PRInt32 aDelta);
|
||||
// Process pending position changed events, then do the position change.
|
||||
// This can wipe out the frametree.
|
||||
nsresult DoInternalPositionChangedSync(PRBool aUp, PRInt32 aDelta);
|
||||
// Actually do the internal position change. This can wipe out the frametree
|
||||
nsresult DoInternalPositionChanged(PRBool aUp, PRInt32 aDelta);
|
||||
nsListScrollSmoother* GetSmoother();
|
||||
void VerticalScroll(PRInt32 aDelta);
|
||||
|
||||
|
@ -132,6 +138,37 @@ public:
|
|||
void PostReflowCallback();
|
||||
|
||||
protected:
|
||||
class nsPositionChangedEvent;
|
||||
friend class nsPositionChangedEvent;
|
||||
|
||||
class nsPositionChangedEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsPositionChangedEvent(nsListBoxBodyFrame* aFrame,
|
||||
PRBool aUp, PRInt32 aDelta) :
|
||||
mFrame(aFrame), mUp(aUp), mDelta(aDelta)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
if (!mFrame) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mFrame->mPendingPositionChangeEvents.RemoveElement(this);
|
||||
|
||||
return mFrame->DoInternalPositionChanged(mUp, mDelta);
|
||||
}
|
||||
|
||||
void Revoke() {
|
||||
mFrame = nsnull;
|
||||
}
|
||||
|
||||
nsListBoxBodyFrame* mFrame;
|
||||
PRBool mUp;
|
||||
PRInt32 mDelta;
|
||||
};
|
||||
|
||||
void ComputeTotalRowCount();
|
||||
void RemoveChildFrame(nsBoxLayoutState &aState, nsIFrame *aChild);
|
||||
|
||||
|
@ -157,6 +194,8 @@ protected:
|
|||
nsListScrollSmoother* mScrollSmoother;
|
||||
PRInt32 mTimePerRow;
|
||||
|
||||
nsTArray< nsRefPtr<nsPositionChangedEvent> > mPendingPositionChangeEvents;
|
||||
|
||||
PRPackedBool mReflowCallbackPosted;
|
||||
};
|
||||
|
||||
|
|
|
@ -1022,7 +1022,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS
|
|||
// XXXbz do we need to notify other view observers for viewmanagers
|
||||
// in our tree?
|
||||
// Make sure to not send WillPaint notifications while scrolling
|
||||
nsViewManager* rootVM = RootViewManager();
|
||||
nsRefPtr<nsViewManager> rootVM = RootViewManager();
|
||||
|
||||
nsIWidget *widget = mRootView->GetWidget();
|
||||
PRBool translucentWindow = PR_FALSE;
|
||||
|
|
Загрузка…
Ссылка в новой задаче