From cbda596f9331f4d72e44baece77c131f9d700959 Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Mon, 26 Sep 2005 01:27:42 +0000 Subject: [PATCH] Make sure to flush out the content model before processing restyles; otherwise we can end up with odd content duplication. Bug 309986, r+sr=dbaron git-svn-id: svn://10.0.0.236/trunk@180938 18797224-902f-48f8-a5cc-f745e15eee43 --- .../html/document/src/nsHTMLContentSink.cpp | 25 ++++++++++++--- mozilla/layout/base/nsCSSFrameConstructor.cpp | 32 +++++++++++++------ 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/mozilla/content/html/document/src/nsHTMLContentSink.cpp b/mozilla/content/html/document/src/nsHTMLContentSink.cpp index 73e03958aff..72b0aef05ff 100644 --- a/mozilla/content/html/document/src/nsHTMLContentSink.cpp +++ b/mozilla/content/html/document/src/nsHTMLContentSink.cpp @@ -3977,10 +3977,20 @@ HTMLContentSink::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType) // notification to occur. Since this could result in frame // creation, make sure we've flushed everything before we // continue. - // Also increment mInNotification to make sure we don't flush again - // until the end of this update, even if nested updates or + + // Note that UPDATE_CONTENT_STATE notifications never cause + // synchronous frame construction, so we never have to worry about + // them here. The code that handles the async event these + // notifications post will flush us out if it needs to. + + // Also, if this is not an UPDATE_CONTENT_STATE notification, + // increment mInNotification to make sure we don't flush again until + // the end of this update, even if nested updates or // FlushPendingNotifications calls happen during it. - if (!mInNotification++ && mCurrentContext) { + NS_ASSERTION(aUpdateType && (aUpdateType & UPDATE_ALL) == aUpdateType, + "Weird update type bitmask"); + if (aUpdateType != UPDATE_CONTENT_STATE && !mInNotification++ && + mCurrentContext) { mCurrentContext->FlushTags(PR_TRUE); } } @@ -3992,8 +4002,13 @@ HTMLContentSink::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType) // something else in the script processing caused the // notification to occur. Update our notion of how much // has been flushed to include any new content if ending - // this update leaves us not inside a notification. - if (!--mInNotification) { + // this update leaves us not inside a notification. Note that we + // exclude UPDATE_CONTENT_STATE notifications here, since those + // never affect the frame model directly while inside the + // notification. + NS_ASSERTION(aUpdateType && (aUpdateType & UPDATE_ALL) == aUpdateType, + "Weird update type bitmask"); + if (aUpdateType != UPDATE_CONTENT_STATE && !--mInNotification) { UpdateAllContexts(); } } diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index 404abfa09d5..0bb9b2ee80b 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -10425,16 +10425,19 @@ nsCSSFrameConstructor::DoContentStateChanged(nsIContent* aContent, NS_ASSERTION(styleSet, "couldn't get style set"); if (aContent) { - nsChangeHint hint; - if (aStateMask & (NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED | - NS_EVENT_STATE_SUPPRESSED)) { - // Any change to a content state that affects which frames we - // construct must lead to a frame reconstruct here - hint = nsChangeHint_ReconstructFrame; - } else { - hint = NS_STYLE_HINT_NONE; - nsIFrame* primaryFrame = mPresShell->GetPrimaryFrameFor(aContent); - if (primaryFrame) { + nsChangeHint hint = NS_STYLE_HINT_NONE; + // Any change to a content state that affects which frames we construct + // must lead to a frame reconstruct here if we already have a frame. + // Note that we never decide through non-CSS means to not create frames + // based on content states, so if we already don't have a frame we don't + // need to force a reframe -- if it's needed, the HasStateDependentStyle + // call will handle things. + nsIFrame* primaryFrame = mPresShell->GetPrimaryFrameFor(aContent); + if (primaryFrame) { + if (aStateMask & (NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED | + NS_EVENT_STATE_SUPPRESSED)) { + hint = nsChangeHint_ReconstructFrame; + } else { PRUint8 app = primaryFrame->GetStyleDisplay()->mAppearance; if (app) { nsITheme *theme = presContext->GetTheme(); @@ -13253,7 +13256,16 @@ void nsCSSFrameConstructor::RestyleEvent::HandleEvent() { NS_ASSERTION(viewManager, "Must have view manager for update"); viewManager->BeginUpdateViewBatch(); + // Force flushing of any pending content notifications that might have queued + // up while our event was pending. That will ensure that we don't construct + // frames for content right now that's still waiting to be notified on, + constructor->mPresShell->GetDocument()-> + FlushPendingNotifications(Flush_ContentAndNotify); + + // Make sure that any restyles that happen from now on will go into + // a new event. constructor->mRestyleEventQueue = nsnull; + constructor->ProcessPendingRestyles(); viewManager->EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC); }