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