Bug 1285474: Add mozilla::RestyleManagerBase to share logic between RestyleManager and ServoRestyleManager
Partially implement some restyling APIs to take rid of some gecko-only code
paths.
MozReview-Commit-ID: L5i6Kr2Qars
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -78,25 +78,22 @@ ElementTagToString(dom::Element* aElemen
nsCString result;
nsDependentAtomString buf(aElement->NodeInfo()->NameAtom());
result.AppendPrintf("(%s@%p)", NS_ConvertUTF16toUTF8(buf).get(), aElement);
return result;
}
#endif
RestyleManager::RestyleManager(nsPresContext* aPresContext)
- : mPresContext(aPresContext)
+ : RestyleManagerBase(aPresContext)
, mDoRebuildAllStyleData(false)
, mInRebuildAllStyleData(false)
- , mObservingRefreshDriver(false)
, mInStyleRefresh(false)
, mSkipAnimationRules(false)
, mHavePendingNonAnimationRestyles(false)
- , mRestyleGeneration(1)
- , mHoverGeneration(0)
, mRebuildAllExtraHint(nsChangeHint(0))
, mRebuildAllRestyleHint(nsRestyleHint(0))
, mAnimationGeneration(0)
, mReframingStyleContexts(nullptr)
, mAnimationsWithDestroyedFrame(nullptr)
, mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR)
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -7,16 +7,17 @@
* Code responsible for managing style changes: tracking what style
* changes need to happen, scheduling them, and doing them.
*/
#ifndef mozilla_RestyleManager_h
#define mozilla_RestyleManager_h
#include "mozilla/RestyleLogging.h"
+#include "RestyleManagerBase.h"
#include "nsISupportsImpl.h"
#include "nsChangeHint.h"
#include "RestyleTracker.h"
#include "nsPresContext.h"
#include "nsRefreshDriver.h"
#include "nsRefPtrHashtable.h"
#include "nsTransitionManager.h"
@@ -28,48 +29,36 @@ namespace mozilla {
enum class CSSPseudoElementType : uint8_t;
class EventStates;
struct UndisplayedNode;
namespace dom {
class Element;
} // namespace dom
-class RestyleManager final
+class RestyleManager final : public RestyleManagerBase
{
public:
- friend class ::nsRefreshDriver;
friend class RestyleTracker;
- typedef mozilla::dom::Element Element;
-
explicit RestyleManager(nsPresContext* aPresContext);
private:
// Private destructor, to discourage deletion outside of Release():
~RestyleManager()
{
MOZ_ASSERT(!mReframingStyleContexts,
"temporary member should be nulled out before destruction");
MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
"leaving dangling pointers from AnimationsWithDestroyedFrame");
}
public:
NS_INLINE_DECL_REFCOUNTING(mozilla::RestyleManager)
- void Disconnect() {
- mPresContext = nullptr;
- }
-
- nsPresContext* PresContext() const {
- MOZ_ASSERT(mPresContext);
- return mPresContext;
- }
-
// Should be called when a frame is going to be destroyed and
// WillDestroyFrameTree hasn't been called yet.
void NotifyDestroyingFrame(nsIFrame* aFrame);
// Forwarded nsIDocumentObserver method, to handle restyling (and
// passing the notification to the frame).
nsresult ContentStateChanged(nsIContent* aContent,
EventStates aStateMask);
@@ -83,24 +72,16 @@ public:
// Forwarded nsIMutationObserver method, to handle restyling (and
// passing the notification to the frame).
void AttributeChanged(Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType,
const nsAttrValue* aOldValue);
- // Get an integer that increments every time we process pending restyles.
- // The value is never 0.
- uint32_t GetRestyleGeneration() const { return mRestyleGeneration; }
-
- // Get an integer that increments every time there is a style change
- // as a result of a change to the :hover content state.
- uint32_t GetHoverGeneration() const { return mHoverGeneration; }
-
// Get a counter that increments on every style change, that we use to
// track whether off-main-thread animations are up-to-date.
uint64_t GetAnimationGeneration() const { return mAnimationGeneration; }
static uint64_t GetAnimationGenerationForFrame(nsIFrame* aFrame);
// Update the animation generation count to mark that animation state
// has changed.
@@ -134,25 +115,23 @@ public:
*/
nsresult ReparentStyleContext(nsIFrame* aFrame);
void ClearSelectors() {
mPendingRestyles.ClearSelectors();
}
private:
- nsCSSFrameConstructor* FrameConstructor() const
- { return PresContext()->FrameConstructor(); }
-
// Used when restyling an element with a frame.
void ComputeAndProcessStyleChange(nsIFrame* aFrame,
nsChangeHint aMinChange,
RestyleTracker& aRestyleTracker,
nsRestyleHint aRestyleHint,
const RestyleHintData& aRestyleHintData);
+
// Used when restyling a display:contents element.
void ComputeAndProcessStyleChange(nsStyleContext* aNewContext,
Element* aElement,
nsChangeHint aMinChange,
RestyleTracker& aRestyleTracker,
nsRestyleHint aRestyleHint,
const RestyleHintData& aRestyleHintData);
@@ -522,44 +501,33 @@ private:
return mDoRebuildAllStyleData &&
&aRestyleTracker == &mPendingRestyles;
}
void ProcessRestyles(RestyleTracker& aRestyleTracker) {
// Fast-path the common case (esp. for the animation restyle
// tracker) of not having anything to do.
if (aRestyleTracker.Count() || ShouldStartRebuildAllFor(aRestyleTracker)) {
- if (++mRestyleGeneration == 0) {
- // Keep mRestyleGeneration from being 0, since that's what
- // nsPresContext::GetRestyleGeneration returns when it no
- // longer has a RestyleManager.
- ++mRestyleGeneration;
- }
+ IncrementRestyleGeneration();
aRestyleTracker.DoProcessRestyles();
}
}
private:
- nsPresContext* mPresContext; // weak, disconnected in Disconnect
-
// True if we need to reconstruct the rule tree the next time we
// process restyles.
bool mDoRebuildAllStyleData : 1;
// True if we're currently in the process of reconstructing the rule tree.
bool mInRebuildAllStyleData : 1;
- // True if we're already waiting for a refresh notification
- bool mObservingRefreshDriver : 1;
// True if we're in the middle of a nsRefreshDriver refresh
bool mInStyleRefresh : 1;
// Whether rule matching should skip styles associated with animation
bool mSkipAnimationRules : 1;
bool mHavePendingNonAnimationRestyles : 1;
- uint32_t mRestyleGeneration;
- uint32_t mHoverGeneration;
nsChangeHint mRebuildAllExtraHint;
nsRestyleHint mRebuildAllRestyleHint;
OverflowChangedTracker mOverflowChangedTracker;
// The total number of animation flushes by this frame constructor.
// Used to keep the layer and animation manager in sync.
uint64_t mAnimationGeneration;
new file mode 100644
--- /dev/null
+++ b/layout/base/RestyleManagerBase.cpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "RestyleManagerBase.h"
+
+namespace mozilla {
+
+RestyleManagerBase::RestyleManagerBase(nsPresContext* aPresContext)
+ : mPresContext(aPresContext)
+ , mRestyleGeneration(1)
+ , mHoverGeneration(0)
+ , mObservingRefreshDriver(false)
+{
+ MOZ_ASSERT(mPresContext);
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/base/RestyleManagerBase.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef mozilla_RestyleManagerBase_h
+#define mozilla_RestyleManagerBase_h
+
+namespace mozilla {
+
+class ServoRestyleManager;
+class RestyleManager;
+
+/**
+ * Class for sharing data and logic common to both RestyleManager and
+ * ServoRestyleManager.
+ */
+class RestyleManagerBase
+{
+protected:
+ explicit RestyleManagerBase(nsPresContext* aPresContext);
+
+public:
+ typedef mozilla::dom::Element Element;
+
+ // Get an integer that increments every time we process pending restyles.
+ // The value is never 0.
+ uint32_t GetRestyleGeneration() const { return mRestyleGeneration; }
+
+ // Get an integer that increments every time there is a style change
+ // as a result of a change to the :hover content state.
+ uint32_t GetHoverGeneration() const { return mHoverGeneration; }
+
+ void SetObservingRefreshDriver(bool aObserving) {
+ mObservingRefreshDriver = aObserving;
+ }
+
+ void Disconnect() { mPresContext = nullptr; }
+
+protected:
+ nsPresContext* mPresContext; // weak, can be null after Disconnect().
+ uint32_t mRestyleGeneration;
+ uint32_t mHoverGeneration;
+ // True if we're already waiting for a refresh notification.
+ bool mObservingRefreshDriver;
+
+ void IncrementRestyleGeneration() {
+ if (++mRestyleGeneration == 0) {
+ // Keep mRestyleGeneration from being 0, since that's what
+ // nsPresContext::GetRestyleGeneration returns when it no
+ // longer has a RestyleManager.
+ ++mRestyleGeneration;
+ }
+ }
+
+ nsPresContext* PresContext() const {
+ MOZ_ASSERT(mPresContext);
+ return mPresContext;
+ }
+
+ nsCSSFrameConstructor* FrameConstructor() const {
+ return PresContext()->FrameConstructor();
+ }
+
+ inline bool IsGecko() const {
+ return !IsServo();
+ }
+
+ inline bool IsServo() const {
+#ifdef MOZ_STYLO
+ return PresContext()->StyleSet()->IsServo();
+#else
+ return false;
+#endif
+ }
+};
+
+} // namespace mozilla
+
+#endif
--- a/layout/base/RestyleManagerHandle.h
+++ b/layout/base/RestyleManagerHandle.h
@@ -130,16 +130,18 @@ public:
inline void AttributeChanged(dom::Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType,
const nsAttrValue* aOldValue);
inline nsresult ReparentStyleContext(nsIFrame* aFrame);
inline bool HasPendingRestyles();
inline uint64_t GetRestyleGeneration() const;
+ inline uint32_t GetHoverGeneration() const;
+ inline void SetObservingRefreshDriver(bool aObserving);
private:
// Stores a pointer to an RestyleManager or a ServoRestyleManager. The least
// significant bit is 0 for the former, 1 for the latter. This is
// valid as the least significant bit will never be used for a pointer
// value on platforms we care about.
uintptr_t mValue;
};
--- a/layout/base/RestyleManagerHandleInlines.h
+++ b/layout/base/RestyleManagerHandleInlines.h
@@ -138,14 +138,27 @@ RestyleManagerHandle::Ptr::HasPendingRes
}
uint64_t
RestyleManagerHandle::Ptr::GetRestyleGeneration() const
{
FORWARD(GetRestyleGeneration, ());
}
+uint32_t
+RestyleManagerHandle::Ptr::GetHoverGeneration() const
+{
+ FORWARD(GetHoverGeneration, ());
+}
+
+void
+RestyleManagerHandle::Ptr::SetObservingRefreshDriver(bool aObserving)
+{
+ FORWARD(SetObservingRefreshDriver, (aObserving));
+}
+
+
} // namespace mozilla
#undef FORWARD
#undef FORWARD_CONCRETE
#endif // mozilla_RestyleManagerHandleInlines_h
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -1,37 +1,57 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/ServoRestyleManager.h"
+#include "mozilla/ServoStyleSet.h"
using namespace mozilla::dom;
namespace mozilla {
-ServoRestyleManager::ServoRestyleManager()
- : mRestyleGeneration(1)
+ServoRestyleManager::ServoRestyleManager(nsPresContext* aPresContext)
+ : RestyleManagerBase(aPresContext)
{
}
void
ServoRestyleManager::Disconnect()
{
NS_ERROR("stylo: ServoRestyleManager::Disconnect not implemented");
}
void
ServoRestyleManager::PostRestyleEvent(Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint)
{
- NS_ERROR("stylo: ServoRestyleManager::PostRestyleEvent not implemented");
+ if (MOZ_UNLIKELY(!mPresContext) ||
+ MOZ_UNLIKELY(mPresContext->PresShell()->IsDestroying())) {
+ return;
+ }
+
+ nsIPresShell* presShell = mPresContext->PresShell();
+ if (!mObservingRefreshDriver) {
+ mObservingRefreshDriver = mPresContext->RefreshDriver()->
+ AddStyleFlushObserver(presShell);
+ }
+
+ aElement->SetIsDirtyForServo();
+ nsINode* cur = aElement;
+ while ((cur = cur->GetParentNode())) {
+ if (cur->HasDirtyDescendantsForServo())
+ break;
+ cur->SetHasDirtyDescendantsForServo();
+ }
+
+ presShell->GetDocument()->SetNeedStyleFlush();
}
void
ServoRestyleManager::PostRestyleEventForLazyConstruction()
{
NS_ERROR("stylo: ServoRestyleManager::PostRestyleEventForLazyConstruction not implemented");
}
@@ -48,17 +68,17 @@ ServoRestyleManager::PostRebuildAllStyle
{
MOZ_CRASH("stylo: ServoRestyleManager::PostRebuildAllStyleDataEvent not implemented");
}
void
ServoRestyleManager::ProcessPendingRestyles()
{
// XXXheycam Do nothing for now.
- mRestyleGeneration++;
+ IncrementRestyleGeneration();
}
void
ServoRestyleManager::RestyleForInsertOrChange(Element* aContainer,
nsIContent* aChild)
{
NS_ERROR("stylo: ServoRestyleManager::RestyleForInsertOrChange not implemented");
}
@@ -77,17 +97,33 @@ ServoRestyleManager::RestyleForRemove(El
{
NS_ERROR("stylo: ServoRestyleManager::RestyleForRemove not implemented");
}
nsresult
ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
EventStates aStateMask)
{
- NS_ERROR("stylo: ServoRestyleManager::ContentStateChanged not implemented");
+ if (!aContent->IsElement()) {
+ return NS_OK;
+ }
+
+ Element* aElement = aContent->AsElement();
+ nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
+ if (primaryFrame) {
+ primaryFrame->ContentStatesChanged(aStateMask);
+ }
+
+ if (aStateMask.HasState(NS_EVENT_STATE_HOVER)) {
+ ++mHoverGeneration;
+ }
+
+ // TODO(emilio): There's a bunch more logic in the normal RestyleManager that
+ // we need to implement.
+ NS_ERROR("stylo: ServoRestyleManager::ContentStateChanged not completely implemented");
return NS_OK;
}
void
ServoRestyleManager::AttributeWillChange(Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType,
@@ -114,15 +150,9 @@ ServoRestyleManager::ReparentStyleContex
bool
ServoRestyleManager::HasPendingRestyles()
{
NS_ERROR("stylo: ServoRestyleManager::HasPendingRestyles not implemented");
return false;
}
-uint64_t
-ServoRestyleManager::GetRestyleGeneration() const
-{
- return mRestyleGeneration;
-}
-
} // namespace mozilla
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -3,40 +3,43 @@
/* 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/. */
#ifndef mozilla_ServoRestyleManager_h
#define mozilla_ServoRestyleManager_h
#include "mozilla/EventStates.h"
+#include "RestyleManagerBase.h"
#include "nsChangeHint.h"
#include "nsISupportsImpl.h"
+#include "nsPresContext.h"
+#include "nsINode.h"
namespace mozilla {
namespace dom {
class Element;
} // namespace dom
} // namespace mozilla
class nsAttrValue;
class nsIAtom;
class nsIContent;
class nsIFrame;
namespace mozilla {
/**
* Restyle manager for a Servo-backed style system.
*/
-class ServoRestyleManager
+class ServoRestyleManager : public RestyleManagerBase
{
public:
NS_INLINE_DECL_REFCOUNTING(ServoRestyleManager)
- ServoRestyleManager();
+ explicit ServoRestyleManager(nsPresContext* aPresContext);
void Disconnect();
void PostRestyleEvent(dom::Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint);
void PostRestyleEventForLazyConstruction();
void RebuildAllStyleData(nsChangeHint aExtraHint,
nsRestyleHint aRestyleHint);
@@ -59,19 +62,25 @@ public:
const nsAttrValue* aNewValue);
void AttributeChanged(dom::Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType,
const nsAttrValue* aOldValue);
nsresult ReparentStyleContext(nsIFrame* aFrame);
bool HasPendingRestyles();
- uint64_t GetRestyleGeneration() const;
protected:
~ServoRestyleManager() {}
- uint64_t mRestyleGeneration;
+private:
+ nsPresContext* PresContext() const { return mPresContext; }
+ nsCSSFrameConstructor* FrameConstructor() const {
+ return mPresContext->FrameConstructor();
+ }
+ inline ServoStyleSet* StyleSet() const {
+ return PresContext()->StyleSet()->AsServo();
+ }
};
} // namespace mozilla
#endif // mozilla_ServoRestyleManager_h
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -102,16 +102,17 @@ EXPORTS += [
EXPORTS.mozilla += [
'ArenaObjectID.h',
'ArenaRefPtr.h',
'ArenaRefPtrInlines.h',
'GeometryUtils.h',
'PaintTracker.h',
'RestyleLogging.h',
'RestyleManager.h',
+ 'RestyleManagerBase.h',
'RestyleManagerHandle.h',
'RestyleManagerHandleInlines.h',
'ServoRestyleManager.h',
'StaticPresData.h',
]
UNIFIED_SOURCES += [
'AccessibleCaret.cpp',
@@ -149,16 +150,17 @@ UNIFIED_SOURCES += [
'nsPresContext.cpp',
'nsPresShell.cpp',
'nsQuoteList.cpp',
'nsStyleChangeList.cpp',
'nsStyleSheetService.cpp',
'PaintTracker.cpp',
'PositionedEventTargeting.cpp',
'RestyleManager.cpp',
+ 'RestyleManagerBase.cpp',
'RestyleTracker.cpp',
'ScrollbarStyles.cpp',
'ServoRestyleManager.cpp',
'StackArena.cpp',
'StaticPresData.cpp',
'TouchManager.cpp',
'ZoomConstraintsClient.cpp',
]
--- a/layout/base/nsCSSRenderingBorders.cpp
+++ b/layout/base/nsCSSRenderingBorders.cpp
@@ -16,16 +16,17 @@
#include "DottedCornerFinder.h"
#include "nsLayoutUtils.h"
#include "nsStyleConsts.h"
#include "nsContentUtils.h"
#include "nsCSSColorUtils.h"
#include "GeckoProfiler.h"
#include "nsExpirationTracker.h"
#include "RoundedRect.h"
+#include "nsIScriptError.h"
#include "nsClassHashtable.h"
#include "nsPresContext.h"
#include "nsStyleStruct.h"
#include "mozilla/gfx/2D.h"
#include "gfx2DGlue.h"
#include "gfxGradientCache.h"
#include <algorithm>
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -3677,33 +3677,28 @@ FlushLayoutRecursive(nsIDocument* aDocum
return true;
}
void
PresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent,
bool aFlushOnHoverChange)
{
RestyleManagerHandle restyleManager = mPresContext->RestyleManager();
- if (restyleManager->IsServo()) {
- NS_ERROR("stylo: cannot dispatch synthetic mouse moves when using a "
- "ServoRestyleManager yet");
- return;
- }
uint32_t hoverGenerationBefore =
- restyleManager->AsGecko()->GetHoverGeneration();
+ restyleManager->GetHoverGeneration();
nsEventStatus status;
nsView* targetView = nsView::GetViewFor(aEvent->mWidget);
if (!targetView)
return;
targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
if (MOZ_UNLIKELY(mIsDestroying)) {
return;
}
if (aFlushOnHoverChange &&
- hoverGenerationBefore != restyleManager->AsGecko()->GetHoverGeneration()) {
+ hoverGenerationBefore != restyleManager->GetHoverGeneration()) {
// Flush so that the resulting reflow happens now so that our caller
// can suppress any synthesized mouse moves caused by that reflow.
// This code only ever runs for the root document, but :hover changes
// can happen in descendant documents too, so make sure we flush
// all of them.
FlushLayoutRecursive(mDocument);
}
}
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1741,20 +1741,17 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
profiler_tracing("Paint", "Styles", mStyleCause, TRACING_INTERVAL_START);
mStyleCause = nullptr;
}
NS_ADDREF(shell);
mStyleFlushObservers.RemoveElement(shell);
RestyleManagerHandle restyleManager =
shell->GetPresContext()->RestyleManager();
- // XXX stylo: ServoRestyleManager does not observer the refresh driver yet.
- if (restyleManager->IsGecko()) {
- restyleManager->AsGecko()->mObservingRefreshDriver = false;
- }
+ restyleManager->SetObservingRefreshDriver(false);
shell->FlushPendingNotifications(ChangesToFlush(Flush_Style, false));
// Inform the FontFaceSet that we ticked, so that it can resolve its
// ready promise if it needs to (though it might still be waiting on
// a layout flush).
nsPresContext* presContext = shell->GetPresContext();
if (presContext) {
presContext->NotifyFontFaceSetOnRefresh();
}