--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -17,16 +17,17 @@
#include "mozilla/LayerAnimationInfo.h"
#include "mozilla/RestyleManagerHandle.h"
#include "mozilla/RestyleManagerHandleInlines.h"
#include "mozilla/StyleAnimationValue.h"
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetPresShellForContent
#include "nsCSSPropertyIDSet.h"
#include "nsCSSProps.h"
#include "nsIPresShell.h"
+#include "nsIPresShellInlines.h"
#include "nsLayoutUtils.h"
#include "nsRuleNode.h" // For nsRuleNode::ComputePropertiesOverridingAnimation
#include "nsRuleProcessorData.h" // For ElementRuleProcessorData etc.
#include "nsTArray.h"
#include <bitset>
#include <initializer_list>
using mozilla::dom::Animation;
@@ -258,17 +259,17 @@ EffectCompositor::RequestRestyle(dom::El
auto& elementsToRestyle = mElementsToRestyle[aCascadeLevel];
PseudoElementHashEntry::KeyType key = { aElement, aPseudoType };
if (aRestyleType == RestyleType::Throttled) {
if (!elementsToRestyle.Contains(key)) {
elementsToRestyle.Put(key, false);
}
- mPresContext->Document()->SetNeedStyleFlush();
+ mPresContext->PresShell()->SetNeedStyleFlush();
} else {
// Get() returns 0 if the element is not found. It will also return
// false if the element is found but does not have a pending restyle.
bool hasPendingRestyle = elementsToRestyle.Get(key);
if (!hasPendingRestyle) {
PostRestyleForAnimation(aElement, aPseudoType, aCascadeLevel);
}
elementsToRestyle.Put(key, true);
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -249,16 +249,17 @@
#include "nsISupportsPrimitives.h"
#include "mozilla/StyleSetHandle.h"
#include "mozilla/StyleSetHandleInlines.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "mozilla/dom/DocGroup.h"
#include "mozilla/dom/TabGroup.h"
+#include "nsIPresShell.h"
#include "mozilla/DocLoadingTimelineMarker.h"
#include "nsISpeculativeConnect.h"
#include "mozilla/MediaManager.h"
#ifdef MOZ_WEBRTC
#include "IPeerConnection.h"
@@ -1308,18 +1309,16 @@ nsIDocument::nsIDocument()
mAllowDNSPrefetch(true),
mIsStaticDocument(false),
mCreatingStaticClone(false),
mInUnlinkOrDeletion(false),
mHasHadScriptHandlingObject(false),
mIsBeingUsedAsImage(false),
mIsSyntheticDocument(false),
mHasLinksToUpdate(false),
- mNeedLayoutFlush(false),
- mNeedStyleFlush(false),
mMayHaveDOMMutationObservers(false),
mMayHaveAnimationObservers(false),
mHasMixedActiveContentLoaded(false),
mHasMixedActiveContentBlocked(false),
mHasMixedDisplayContentLoaded(false),
mHasMixedDisplayContentBlocked(false),
mHasMixedContentObjectSubrequest(false),
mHasCSP(false),
@@ -1387,17 +1386,16 @@ nsDocument::nsDocument(const char* aCont
, mHeaderData(nullptr)
, mIsGoingAway(false)
, mInDestructor(false)
, mMayHaveTitleElement(false)
, mHasWarnedAboutBoxObjects(false)
, mDelayFrameLoaderInitialization(false)
, mSynchronousDOMContentLoaded(false)
, mInXBLUpdate(false)
- , mInFlush(false)
, mParserAborted(false)
, mCurrentOrientationAngle(0)
, mCurrentOrientationType(OrientationType::Portrait_primary)
, mSSApplicableStateNotificationPending(false)
, mReportedUseCounters(false)
, mStyleSetFilled(false)
, mPendingFullscreenRequests(0)
, mXMLDeclarationBits(0)
@@ -7935,37 +7933,22 @@ nsDocument::FlushPendingNotifications(Fl
// correct size to determine the correct style.
if (mParentDocument && IsSafeToFlush()) {
FlushType parentType = aType;
if (aType >= FlushType::Style)
parentType = std::max(FlushType::Layout, aType);
mParentDocument->FlushPendingNotifications(parentType);
}
- // We can optimize away getting our presshell and calling
- // FlushPendingNotifications on it if we don't need a flush of the sort we're
- // looking at. The one exception is if mInFlush is true, because in that
- // case we might have set mNeedStyleFlush and mNeedLayoutFlush to false
- // already but the presshell hasn't actually done the corresponding work yet.
- // So if mInFlush and reentering this code, we need to flush the presshell.
- if (mNeedStyleFlush ||
- (mNeedLayoutFlush && aType >= FlushType::InterruptibleLayout) ||
- aType >= FlushType::Display ||
- mInFlush) {
- nsCOMPtr<nsIPresShell> shell = GetShell();
- if (shell) {
- mNeedStyleFlush = false;
- mNeedLayoutFlush = mNeedLayoutFlush && (aType < FlushType::InterruptibleLayout);
- // mInFlush is a bitfield, so can't us AutoRestore here. But we
- // need to keep track of multi-level reentry correctly, so need
- // to restore the old mInFlush value.
- bool oldInFlush = mInFlush;
- mInFlush = true;
- shell->FlushPendingNotifications(aType);
- mInFlush = oldInFlush;
+ // Call nsIPresShell::NeedFlush (inline, non-virtual) to check whether we
+ // really need to flush the shell (virtual, and needs a strong reference).
+ if (nsIPresShell* shell = GetShell()) {
+ if (shell->NeedFlush(aType)) {
+ nsCOMPtr<nsIPresShell> presShell = shell;
+ presShell->FlushPendingNotifications(aType);
}
}
}
static bool
Copy(nsIDocument* aDocument, void* aData)
{
nsTArray<nsCOMPtr<nsIDocument> >* resources =
@@ -12884,17 +12867,19 @@ nsIDocument::RebuildUserFontSet()
if (!mGetUserFontSetCalled) {
// We want to lazily build the user font set the first time it's
// requested (so we don't force creation of rule cascades too
// early), so don't do anything now.
return;
}
mFontFaceSetDirty = true;
- SetNeedStyleFlush();
+ if (nsIPresShell* shell = GetShell()) {
+ shell->SetNeedStyleFlush();
+ }
// Somebody has already asked for the user font set, so we need to
// post an event to rebuild it. Setting the user font set to be dirty
// and lazily rebuilding it isn't sufficient, since it is only the act
// of rebuilding it that will trigger the style change reflow that
// calls GetUserFontSet. (This reflow causes rebuilding of text runs,
// which starts font loads, whose completion causes another style
// change reflow).
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -1440,20 +1440,16 @@ public:
bool mHasWarnedAboutBoxObjects:1;
bool mDelayFrameLoaderInitialization:1;
bool mSynchronousDOMContentLoaded:1;
bool mInXBLUpdate:1;
- // Whether we're currently under a FlushPendingNotifications call to
- // our presshell. This is used to handle flush reentry correctly.
- bool mInFlush:1;
-
// Parser aborted. True if the parser of this document was forcibly
// terminated instead of letting it finish at its own pace.
bool mParserAborted:1;
friend class nsCallRequestFullScreen;
// ScreenOrientation "pending promise" as described by
// http://www.w3.org/TR/screen-orientation/
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2472,30 +2472,16 @@ public:
bool asError = false,
const char16_t **aParams = nullptr,
uint32_t aParamsLength = 0) const;
virtual void PostVisibilityUpdateEvent() = 0;
bool IsSyntheticDocument() const { return mIsSyntheticDocument; }
- void SetNeedLayoutFlush() {
- mNeedLayoutFlush = true;
- if (mDisplayDocument) {
- mDisplayDocument->SetNeedLayoutFlush();
- }
- }
-
- void SetNeedStyleFlush() {
- mNeedStyleFlush = true;
- if (mDisplayDocument) {
- mDisplayDocument->SetNeedStyleFlush();
- }
- }
-
// Note: nsIDocument is a sub-class of nsINode, which has a
// SizeOfExcludingThis function. However, because nsIDocument objects can
// only appear at the top of the DOM tree, we have a specialized measurement
// function which returns multiple sizes.
virtual void DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const;
// DocAddSizeOfIncludingThis doesn't need to be overridden by sub-classes
// because nsIDocument inherits from nsINode; see the comment above the
// declaration of nsINode::SizeOfIncludingThis.
@@ -3119,22 +3105,16 @@ protected:
// True is this document is synthetic : stand alone image, video, audio
// file, etc.
bool mIsSyntheticDocument : 1;
// True if this document has links whose state needs updating
bool mHasLinksToUpdate : 1;
- // True if a layout flush might not be a no-op
- bool mNeedLayoutFlush : 1;
-
- // True if a style flush might not be a no-op
- bool mNeedStyleFlush : 1;
-
// True if a DOMMutationObserver is perhaps attached to a node in the document.
bool mMayHaveDOMMutationObservers : 1;
// True if an nsIAnimationObserver is perhaps attached to a node in the document.
bool mMayHaveAnimationObservers : 1;
// True if a document has loaded Mixed Active Script (see nsMixedContentBlocker.cpp)
bool mHasMixedActiveContentLoaded : 1;
--- a/dom/smil/nsSMILAnimationController.cpp
+++ b/dom/smil/nsSMILAnimationController.cpp
@@ -11,16 +11,17 @@
#include "nsITimer.h"
#include "mozilla/dom/Element.h"
#include "nsIDocument.h"
#include "mozilla/dom/SVGAnimationElement.h"
#include "nsSMILTimedElement.h"
#include <algorithm>
#include "mozilla/AutoRestore.h"
#include "RestyleTracker.h"
+#include "nsIPresShell.h"
using namespace mozilla;
using namespace mozilla::dom;
//----------------------------------------------------------------------
// nsSMILAnimationController implementation
//----------------------------------------------------------------------
@@ -788,10 +789,12 @@ nsSMILAnimationController::GetRefreshDri
nsPresContext* context = shell->GetPresContext();
return context ? context->RefreshDriver() : nullptr;
}
void
nsSMILAnimationController::FlagDocumentNeedsFlush()
{
- mDocument->SetNeedStyleFlush();
+ if (nsIPresShell* shell = mDocument->GetShell()) {
+ shell->SetNeedStyleFlush();
+ }
}
--- a/dom/xbl/nsBindingManager.cpp
+++ b/dom/xbl/nsBindingManager.cpp
@@ -15,16 +15,17 @@
#include "nsIChannel.h"
#include "nsXPIDLString.h"
#include "plstr.h"
#include "nsIContent.h"
#include "nsIDOMElement.h"
#include "nsIDocument.h"
#include "nsContentUtils.h"
#include "nsIPresShell.h"
+#include "nsIPresShellInlines.h"
#include "nsIXMLContentSink.h"
#include "nsContentCID.h"
#include "mozilla/dom/XMLDocument.h"
#include "nsIStreamListener.h"
#include "ChildIterator.h"
#include "nsITimer.h"
#include "nsXBLBinding.h"
@@ -333,17 +334,19 @@ nsBindingManager::AddToAttachedQueue(nsX
// If we're in the middle of processing our queue already, don't
// bother posting the event.
if (!mProcessingAttachedStack && !mProcessAttachedQueueEvent) {
PostProcessAttachedQueueEvent();
}
// Make sure that flushes will flush out the new items as needed.
- mDocument->SetNeedStyleFlush();
+ if (nsIPresShell* shell = mDocument->GetShell()) {
+ shell->SetNeedStyleFlush();
+ }
return NS_OK;
}
void
nsBindingManager::PostProcessAttachedQueueEvent()
{
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -791,26 +791,29 @@ nsIPresShell::nsIPresShell()
, mIsThemeSupportDisabled(false)
, mIsActive(false)
, mFrozen(false)
, mIsFirstPaint(false)
, mObservesMutationsForPrint(false)
, mReflowScheduled(false)
, mSuppressInterruptibleReflows(false)
, mScrollPositionClampingScrollPortSizeSet(false)
+ , mNeedLayoutFlush(true)
+ , mNeedStyleFlush(true)
, mPresShellId(0)
, mFontSizeInflationEmPerLine(0)
, mFontSizeInflationMinTwips(0)
, mFontSizeInflationLineThreshold(0)
, mFontSizeInflationForceEnabled(false)
, mFontSizeInflationDisabledInMasterProcess(false)
, mFontSizeInflationEnabled(false)
, mPaintingIsFrozen(false)
, mFontSizeInflationEnabledIsDirty(false)
, mIsNeverPainting(false)
+ , mInFlush(false)
{}
PresShell::PresShell()
: mCaretEnabled(false)
#ifdef DEBUG
, mInVerifyReflow(false)
, mCurrentReflowRoot(nullptr)
, mUpdateCount(0)
@@ -2022,17 +2025,17 @@ PresShell::ResizeReflowIgnoreOverride(ns
this, 15,
nsITimer::TYPE_ONE_SHOT);
}
} else {
RefPtr<nsRunnableMethod<PresShell> > resizeEvent =
NewRunnableMethod(this, &PresShell::FireResizeEvent);
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent))) {
mResizeEvent = resizeEvent;
- mDocument->SetNeedStyleFlush();
+ SetNeedStyleFlush();
}
}
}
return NS_OK; //XXX this needs to be real. MMP
}
void
@@ -2768,17 +2771,17 @@ PresShell::FrameNeedsReflow(nsIFrame *aF
// up the tree until we reach either a frame that's already dirty or
// a reflow root.
nsIFrame *f = subtreeRoot;
for (;;) {
if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) {
// we've hit a reflow root or the root frame
if (!wasDirty) {
mDirtyRoots.AppendElement(f);
- mDocument->SetNeedLayoutFlush();
+ SetNeedLayoutFlush();
}
#ifdef DEBUG
else {
VerifyHasDirtyRootAncestor(f);
}
#endif
break;
@@ -3495,17 +3498,19 @@ PresShell::ScrollContentIntoView(nsICont
data->mContentScrollHAxis = aHorizontal;
data->mContentToScrollToFlags = aFlags;
if (NS_FAILED(mContentToScrollTo->SetProperty(nsGkAtoms::scrolling, data,
nsINode::DeleteProperty<PresShell::ScrollIntoViewData>))) {
mContentToScrollTo = nullptr;
}
// Flush layout and attempt to scroll in the process.
- composedDoc->SetNeedLayoutFlush();
+ if (nsIPresShell* shell = composedDoc->GetShell()) {
+ shell->SetNeedLayoutFlush();
+ }
composedDoc->FlushPendingNotifications(FlushType::InterruptibleLayout);
// If mContentToScrollTo is non-null, that means we interrupted the reflow
// (or suppressed it altogether because we're suppressing interruptible
// flushes right now) and won't necessarily get the position correct, but do
// a best-effort scroll here. The other option would be to do this inside
// FlushPendingNotifications, but I'm not sure the repeated scrolling that
// could trigger if reflows keep getting interrupted would be more desirable
@@ -3722,19 +3727,17 @@ PresShell::ScheduleViewManagerFlush(Pain
}
return;
}
nsPresContext* presContext = GetPresContext();
if (presContext) {
presContext->RefreshDriver()->ScheduleViewManagerFlush();
}
- if (mDocument) {
- mDocument->SetNeedLayoutFlush();
- }
+ SetNeedLayoutFlush();
}
bool
FlushLayoutRecursive(nsIDocument* aDocument,
void* aData = nullptr)
{
MOZ_ASSERT(!aData);
nsCOMPtr<nsIDocument> kungFuDeathGrip(aDocument);
@@ -4062,17 +4065,17 @@ PresShell::FlushPendingNotifications(Flu
}
void
PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
{
/**
* VERY IMPORTANT: If you add some sort of new flushing to this
* method, make sure to add the relevant SetNeedLayoutFlush or
- * SetNeedStyleFlush calls on the document.
+ * SetNeedStyleFlush calls on the shell.
*/
FlushType flushType = aFlush.mFlushType;
#ifdef MOZ_GECKO_PROFILER
static const EnumeratedArray<FlushType,
FlushType::Count,
const char*> flushTypeNames = {
"",
@@ -4096,16 +4099,28 @@ PresShell::FlushPendingNotifications(moz
NS_ASSERTION(!accService->IsProcessingRefreshDriverNotification(),
"Flush during accessible tree update!");
}
#endif
#endif
NS_ASSERTION(flushType >= FlushType::Frames, "Why did we get called?");
+ // Record that we are in a flush, so that our optimization in
+ // nsDocument::FlushPendingNotifications doesn't skip any re-entrant
+ // calls to us. Otherwise, we might miss some needed flushes, since
+ // we clear mNeedStyleFlush / mNeedLayoutFlush here at the top of
+ // the function but we might not have done the work yet.
+ AutoRestore<bool> guard(mInFlush);
+ mInFlush = true;
+
+ mNeedStyleFlush = false;
+ mNeedLayoutFlush =
+ mNeedLayoutFlush && (flushType < FlushType::InterruptibleLayout);
+
bool isSafeToFlush = IsSafeToFlush();
// If layout could possibly trigger scripts, then it's only safe to flush if
// it's safe to run script.
bool hasHadScriptObject;
if (mDocument->GetScriptHandlingObject(hasHadScriptObject) ||
hasHadScriptObject) {
isSafeToFlush = isSafeToFlush && nsContentUtils::IsSafeToRunScript();
@@ -4219,27 +4234,27 @@ PresShell::FlushPendingNotifications(moz
if (flushType >= FlushType::Layout) {
if (!mIsDestroying) {
viewManager->UpdateWidgetGeometry();
}
}
}
if (!didStyleFlush && flushType >= FlushType::Style && !mIsDestroying) {
- mDocument->SetNeedStyleFlush();
+ SetNeedStyleFlush();
}
if (!didLayoutFlush && !mIsDestroying &&
(flushType >=
(mSuppressInterruptibleReflows ? FlushType::Layout
: FlushType::InterruptibleLayout))) {
// We suppressed this flush due to mSuppressInterruptibleReflows or
- // !isSafeToFlush, but the document thinks it doesn't
- // need to flush anymore. Let it know what's really going on.
- mDocument->SetNeedLayoutFlush();
+ // !isSafeToFlush, but now we think we don't need to flush any more.
+ // Record what's really going on.
+ SetNeedLayoutFlush();
}
}
void
PresShell::CharacterDataChanged(nsIDocument *aDocument,
nsIContent* aContent,
CharacterDataChangeInfo* aInfo)
{
@@ -9289,17 +9304,17 @@ PresShell::DoReflow(nsIFrame* target, bo
if (f == target) {
break;
}
}
}
NS_ASSERTION(NS_SUBTREE_DIRTY(target), "Why is the target not dirty?");
mDirtyRoots.AppendElement(target);
- mDocument->SetNeedLayoutFlush();
+ SetNeedLayoutFlush();
// Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target)
// assertion so that if it fails it's easier to see what's going on.
#ifdef NOISY_INTERRUPTIBLE_REFLOW
printf("mFramesToDirty.Count() == %u\n", mFramesToDirty.Count());
#endif /* NOISY_INTERRUPTIBLE_REFLOW */
mFramesToDirty.Clear();
@@ -9426,18 +9441,18 @@ PresShell::ProcessReflowCommands(bool aI
// If any new reflow commands were enqueued during the reflow, schedule
// another reflow event to process them. Note that we want to do this
// after DidDoReflow(), since that method can change whether there are
// dirty roots around by flushing, and there's no point in posting a
// reflow event just to have the flush revoke it.
if (!mDirtyRoots.IsEmpty()) {
MaybeScheduleReflow();
- // And tell our document that we might need flushing
- mDocument->SetNeedLayoutFlush();
+ // And record that we might need flushing
+ SetNeedLayoutFlush();
}
}
}
if (!mIsDestroying && mShouldUnsuppressPainting &&
mDirtyRoots.IsEmpty()) {
// We only unlock if we're out of reflows. It's pointless
// to unlock if reflows are still pending, since reflows
--- a/layout/base/RestyleManagerBase.cpp
+++ b/layout/base/RestyleManagerBase.cpp
@@ -2,16 +2,17 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/RestyleManagerBase.h"
#include "mozilla/StyleSetHandleInlines.h"
#include "nsIFrame.h"
+#include "nsIPresShellInlines.h"
namespace mozilla {
RestyleManagerBase::RestyleManagerBase(nsPresContext* aPresContext)
: mPresContext(aPresContext)
, mRestyleGeneration(1)
, mHoverGeneration(0)
, mObservingRefreshDriver(false)
@@ -213,17 +214,17 @@ RestyleManagerBase::PostRestyleEventInte
if (!ObservingRefreshDriver() && !inRefresh) {
SetObservingRefreshDriver(PresContext()->RefreshDriver()->
AddStyleFlushObserver(presShell));
}
// Unconditionally flag our document as needing a flush. The other
// option here would be a dedicated boolean to track whether we need
// to do so (set here and unset in ProcessPendingRestyles).
- presShell->GetDocument()->SetNeedStyleFlush();
+ presShell->SetNeedStyleFlush();
}
/**
* Frame construction helpers follow.
*/
#ifdef DEBUG
static bool gInApplyRenderingChangeToTree = false;
#endif
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -45,16 +45,17 @@ EXPORTS += [
'nsFrameManager.h',
'nsFrameManagerBase.h',
'nsFrameTraversal.h',
'nsIFrameTraversal.h',
'nsILayoutDebugger.h',
'nsILayoutHistoryState.h',
'nsIPercentBSizeObserver.h',
'nsIPresShell.h',
+ 'nsIPresShellInlines.h',
'nsIReflowCallback.h',
'nsLayoutUtils.h',
'nsPresArena.h',
'nsPresArenaObjectList.h',
'nsPresContext.h',
'nsPresState.h',
'nsRefreshDriver.h',
'nsStyleChangeList.h',
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -116,16 +116,17 @@
#include "nsMathMLParts.h"
#include "mozilla/dom/SVGTests.h"
#include "nsSVGUtils.h"
#include "nsRefreshDriver.h"
#include "nsRuleProcessorData.h"
#include "nsTextNode.h"
#include "ActiveLayerTracker.h"
+#include "nsIPresShellInlines.h"
using namespace mozilla;
using namespace mozilla::dom;
// An alias for convenience.
static const nsIFrame::ChildListID kPrincipalList = nsIFrame::kPrincipalList;
nsIFrame*
@@ -12914,8 +12915,28 @@ Iterator::DeleteItemsTo(const Iterator&
NS_ASSERTION(!IsDone(), "Ran off end of list?");
FrameConstructionItem* item = mCurrent;
Next();
item->remove();
mList.AdjustCountsForItem(item, -1);
delete item;
} while (*this != aEnd);
}
+
+void
+nsCSSFrameConstructor::QuotesDirty()
+{
+ NS_PRECONDITION(mUpdateCount != 0, "Instant quote updates are bad news");
+ mQuotesDirty = true;
+ if (nsIPresShell* shell = mDocument->GetShell()) {
+ shell->SetNeedLayoutFlush();
+ }
+}
+
+void
+nsCSSFrameConstructor::CountersDirty()
+{
+ NS_PRECONDITION(mUpdateCount != 0, "Instant counter updates are bad news");
+ mCountersDirty = true;
+ if (nsIPresShell* shell = mDocument->GetShell()) {
+ shell->SetNeedLayoutFlush();
+ }
+}
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -18,16 +18,17 @@
#include "nsCOMPtr.h"
#include "nsILayoutHistoryState.h"
#include "nsQuoteList.h"
#include "nsCounterManager.h"
#include "nsIAnonymousContentCreator.h"
#include "nsFrameManager.h"
#include "ScrollbarStyles.h"
+#include "nsIPresShellInlines.h"
struct nsFrameItems;
class nsStyleContext;
struct nsStyleDisplay;
struct nsGenConInitializer;
class nsContainerFrame;
class nsFirstLineFrame;
@@ -2056,27 +2057,18 @@ private:
// see if aContent and aSibling are legitimate siblings due to restrictions
// imposed by table columns
// XXXbz this code is generally wrong, since the frame for aContent
// may be constructed based on tag, not based on aDisplay!
bool IsValidSibling(nsIFrame* aSibling,
nsIContent* aContent,
mozilla::StyleDisplay& aDisplay);
- void QuotesDirty() {
- NS_PRECONDITION(mUpdateCount != 0, "Instant quote updates are bad news");
- mQuotesDirty = true;
- mDocument->SetNeedLayoutFlush();
- }
-
- void CountersDirty() {
- NS_PRECONDITION(mUpdateCount != 0, "Instant counter updates are bad news");
- mCountersDirty = true;
- mDocument->SetNeedLayoutFlush();
- }
+ void QuotesDirty();
+ void CountersDirty();
/**
* Add the pair (aContent, aStyleContext) to the undisplayed items
* in aList as needed. This method enforces the invariant that all
* style contexts in the undisplayed content map must be non-pseudo
* contexts and also handles unbinding undisplayed generated content
* as needed.
*/
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -581,16 +581,43 @@ public:
* nsIDocument::FlushPendingNotifications.
*
* @param aType the type of notifications to flush
*/
virtual void FlushPendingNotifications(mozilla::FlushType aType) = 0;
virtual void FlushPendingNotifications(mozilla::ChangesToFlush aType) = 0;
/**
+ * Whether we might need a flush for the given flush type. If this
+ * function returns false, we definitely don't need to flush.
+ *
+ * @param aFlushType The flush type to check. This must be
+ * >= FlushType::Style.
+ */
+ bool NeedFlush(mozilla::FlushType aType) const
+ {
+ // We check mInFlush to handle re-entrant calls to FlushPendingNotifications
+ // by reporting that we always need a flush in that case. Otherwise,
+ // we could end up missing needed flushes, since we clear mNeedStyleFlush
+ // and mNeedLayoutFlush at the top of FlushPendingNotifications.
+ //
+ // XXXheycam Could we just clear those flags after the work has been
+ // done instead?
+ MOZ_ASSERT(aType >= mozilla::FlushType::Style);
+ return mNeedStyleFlush ||
+ (mNeedLayoutFlush &&
+ aType >= mozilla::FlushType::InterruptibleLayout) ||
+ aType >= mozilla::FlushType::Display ||
+ mInFlush;
+ }
+
+ inline void SetNeedStyleFlush();
+ inline void SetNeedLayoutFlush();
+
+ /**
* Callbacks will be called even if reflow itself fails for
* some reason.
*/
virtual nsresult PostReflowCallback(nsIReflowCallback* aCallback) = 0;
virtual void CancelReflowCallback(nsIReflowCallback* aCallback) = 0;
virtual void ClearFrameRefs(nsIFrame* aFrame) = 0;
@@ -1800,16 +1827,22 @@ protected:
// If true, we have a reflow scheduled. Guaranteed to be false if
// mReflowContinueTimer is non-null.
bool mReflowScheduled : 1;
bool mSuppressInterruptibleReflows : 1;
bool mScrollPositionClampingScrollPortSizeSet : 1;
+ // True if a layout flush might not be a no-op
+ bool mNeedLayoutFlush : 1;
+
+ // True if a style flush might not be a no-op
+ bool mNeedStyleFlush : 1;
+
uint32_t mPresShellId;
// List of subtrees rooted at style scope roots that need to be restyled.
// When a change to a scoped style sheet is made, we add the style scope
// root to this array rather than setting mStylesHaveChanged = true, since
// we know we don't need to restyle the whole document. However, if in the
// same update block we have already had other changes that require
// the whole document to be restyled (i.e., mStylesHaveChanged is already
@@ -1830,13 +1863,17 @@ protected:
// Dirty bit indicating that mFontSizeInflationEnabled needs to be recomputed.
bool mFontSizeInflationEnabledIsDirty;
// If a document belongs to an invisible DocShell, this flag must be set
// to true, so we can avoid any paint calls for widget related to this
// presshell.
bool mIsNeverPainting;
+
+ // Whether we're currently under a FlushPendingNotifications.
+ // This is used to handle flush reentry correctly.
+ bool mInFlush;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIPresShell, NS_IPRESSHELL_IID)
#endif /* nsIPresShell_h___ */
new file mode 100644
--- /dev/null
+++ b/layout/base/nsIPresShellInlines.h
@@ -0,0 +1,28 @@
+#ifndef nsIPresShellInlines_h
+#define nsIPresShellInlines_h
+
+#include "nsIDocument.h"
+
+void
+nsIPresShell::SetNeedLayoutFlush()
+{
+ mNeedLayoutFlush = true;
+ if (nsIDocument* doc = mDocument->GetDisplayDocument()) {
+ if (nsIPresShell* shell = doc->GetShell()) {
+ shell->mNeedLayoutFlush = true;
+ }
+ }
+}
+
+void
+nsIPresShell::SetNeedStyleFlush()
+{
+ mNeedStyleFlush = true;
+ if (nsIDocument* doc = mDocument->GetDisplayDocument()) {
+ if (nsIPresShell* shell = doc->GetShell()) {
+ shell->mNeedStyleFlush = true;
+ }
+ }
+}
+
+#endif // nsIPresShellInlines_h
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -2064,22 +2064,22 @@ nsPresContext::MediaFeatureValuesChanged
}
void
nsPresContext::PostMediaFeatureValuesChangedEvent()
{
// FIXME: We should probably replace this event with use of
// nsRefreshDriver::AddStyleFlushObserver (except the pres shell would
// need to track whether it's been added).
- if (!mPendingMediaFeatureValuesChanged) {
+ if (!mPendingMediaFeatureValuesChanged && mShell) {
nsCOMPtr<nsIRunnable> ev =
NewRunnableMethod(this, &nsPresContext::HandleMediaFeatureValuesChangedEvent);
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
mPendingMediaFeatureValuesChanged = true;
- mDocument->SetNeedStyleFlush();
+ mShell->SetNeedStyleFlush();
}
}
}
void
nsPresContext::HandleMediaFeatureValuesChangedEvent()
{
// Null-check mShell in case the shell has been destroyed (and the
@@ -2253,17 +2253,19 @@ void
nsPresContext::RebuildCounterStyles()
{
if (mCounterStyleManager->IsInitial()) {
// Still in its initial state, no need to reset.
return;
}
mCounterStylesDirty = true;
- mDocument->SetNeedStyleFlush();
+ if (mShell) {
+ mShell->SetNeedStyleFlush();
+ }
if (!mPostedFlushCounterStyles) {
nsCOMPtr<nsIRunnable> ev =
NewRunnableMethod(this, &nsPresContext::HandleRebuildCounterStyles);
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
mPostedFlushCounterStyles = true;
}
}
}
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -450,17 +450,17 @@ nsAnimationManager::UpdateAnimations(nsS
newAnimations[newAnimIdx]->CancelFromStyle();
}
// We don't actually dispatch the pending events now. We'll either
// dispatch them the next time we get a refresh driver notification
// or the next time somebody calls
// nsPresShell::FlushPendingNotifications.
if (mEventDispatcher.HasQueuedEvents()) {
- mPresContext->Document()->SetNeedStyleFlush();
+ mPresContext->PresShell()->SetNeedStyleFlush();
}
}
void
nsAnimationManager::StopAnimationsForElement(
mozilla::dom::Element* aElement,
mozilla::CSSPseudoElementType aPseudoType)
{
--- a/view/nsViewManager.cpp
+++ b/view/nsViewManager.cpp
@@ -224,20 +224,19 @@ nsViewManager::SetWindowDimensions(nscoo
// request a resize reflow (which would correct it). See bug 617076.
mDelayedResize = nsSize(aWidth, aHeight);
FlushDelayedResize(false);
}
mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
DoSetWindowDimensions(aWidth, aHeight);
} else {
mDelayedResize.SizeTo(aWidth, aHeight);
- if (mPresShell && mPresShell->GetDocument()) {
- nsIDocument* doc = mPresShell->GetDocument();
- doc->SetNeedStyleFlush();
- doc->SetNeedLayoutFlush();
+ if (mPresShell) {
+ mPresShell->SetNeedStyleFlush();
+ mPresShell->SetNeedLayoutFlush();
}
}
}
}
void
nsViewManager::FlushDelayedResize(bool aDoReflow)
{