Bug 1373018 - Part 11: stylo: Move cached style structs to GeckoStyleContext; r?bholley
MozReview-Commit-ID: 1LA8AJ3oNwF
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -1913,17 +1913,17 @@ ElementRestyler::Restyle(nsRestyleHint a
}
// Turns out we couldn't stop restyling here. Process the struct
// swaps that RestyleSelf would've done had we not returned
// RestyleResult::eStopWithStyleChange.
for (SwapInstruction& swap : swaps) {
LOG_RESTYLE("swapping style structs between %p and %p",
swap.mOldContext.get(), swap.mNewContext.get());
- swap.mOldContext->SwapStyleData(swap.mNewContext, swap.mStructsToSwap);
+ swap.mOldContext->AsGecko()->SwapStyleData(swap.mNewContext->AsGecko(), swap.mStructsToSwap);
swappedStructs |= swap.mStructsToSwap;
}
swaps.Clear();
}
if (!swappedStructs) {
// If we swapped any structs from the old context, then we need to keep
// it alive until after the RestyleChildren call so that we can fix up
@@ -2748,27 +2748,27 @@ ElementRestyler::RestyleSelf(nsIFrame* a
oldContext.get(), newContext.get());
SwapInstruction* swap = aSwaps.AppendElement();
swap->mOldContext = oldContext;
swap->mNewContext = newContext;
swap->mStructsToSwap = equalStructs;
} else {
LOG_RESTYLE("swapping style structs between %p and %p",
oldContext.get(), newContext.get());
- oldContext->SwapStyleData(newContext, equalStructs);
+ oldContext->AsGecko()->SwapStyleData(newContext->AsGecko(), equalStructs);
*aSwappedStructs |= equalStructs;
}
#ifdef RESTYLE_LOGGING
uint32_t structs = GeckoRestyleManager::StructsToLog() & equalStructs;
if (structs) {
LOG_RESTYLE_INDENT();
LOG_RESTYLE("old style context now has: %s",
- oldContext->GetCachedStyleDataAsString(structs).get());
+ oldContext->AsGecko()->GetCachedStyleDataAsString(structs).get());
LOG_RESTYLE("new style context now has: %s",
- newContext->GetCachedStyleDataAsString(structs).get());
+ newContext->AsGecko()->GetCachedStyleDataAsString(structs).get());
}
#endif
}
LOG_RESTYLE("setting new style context");
aSelf->SetStyleContext(newContext);
}
} else {
LOG_RESTYLE("not setting new style context, since we'll reframe");
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -83,17 +83,17 @@ RestyleTracker::ProcessOneRestyle(Elemen
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
if (aRestyleHint & ~eRestyle_LaterSiblings) {
#ifdef RESTYLE_LOGGING
if (ShouldLogRestyle() && primaryFrame &&
GeckoRestyleManager::StructsToLog() != 0) {
LOG_RESTYLE("style context tree before restyle:");
LOG_RESTYLE_INDENT();
- primaryFrame->StyleContext()->LogStyleContextTree(
+ primaryFrame->StyleContext()->AsGecko()->LogStyleContextTree(
LoggingDepth(), GeckoRestyleManager::StructsToLog());
}
#endif
mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
*this, aRestyleHint, aRestyleHintData);
} else if (aChangeHint &&
(primaryFrame ||
(aChangeHint & nsChangeHint_ReconstructFrame))) {
--- a/layout/style/GeckoStyleContext.cpp
+++ b/layout/style/GeckoStyleContext.cpp
@@ -18,16 +18,17 @@
using namespace mozilla;
GeckoStyleContext::GeckoStyleContext(nsStyleContext* aParent,
nsIAtom* aPseudoTag,
CSSPseudoElementType aPseudoType,
already_AddRefed<nsRuleNode> aRuleNode,
bool aSkipParentDisplayBasedStyleFixup)
: nsStyleContext(aParent, aPseudoTag, aPseudoType)
+ , mCachedResetData(nullptr)
, mChild(nullptr)
, mEmptyChild(nullptr)
, mRuleNode(Move(aRuleNode))
{
mBits |= NS_STYLE_CONTEXT_IS_GECKO;
if (aParent) {
#ifdef DEBUG
@@ -351,19 +352,91 @@ GeckoStyleContext::SetIneligibleForShari
do {
child->SetIneligibleForSharing();
child = child->mNextSibling;
} while (mEmptyChild != child);
}
}
#ifdef RESTYLE_LOGGING
+nsCString
+GeckoStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
+{
+ nsCString structs;
+ for (nsStyleStructID i = nsStyleStructID(0);
+ i < nsStyleStructID_Length;
+ i = nsStyleStructID(i + 1)) {
+ if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
+ const void* data = GetCachedStyleData(i);
+ if (!structs.IsEmpty()) {
+ structs.Append(' ');
+ }
+ structs.AppendPrintf("%s=%p", StructName(i), data);
+ if (HasCachedDependentStyleData(i)) {
+ structs.AppendLiteral("(dependent)");
+ } else {
+ structs.AppendLiteral("(owned)");
+ }
+ }
+ }
+ return structs;
+}
+
+int32_t&
+GeckoStyleContext::LoggingDepth()
+{
+ static int32_t depth = 0;
+ return depth;
+}
+
void
-GeckoStyleContext::LogChildStyleContextTree(uint32_t aStructs) const
+GeckoStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
+{
+ LoggingDepth() = aLoggingDepth;
+ LogStyleContextTree(true, aStructs);
+}
+
+void
+GeckoStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
{
+ nsCString structs = GetCachedStyleDataAsString(aStructs);
+ if (!structs.IsEmpty()) {
+ structs.Append(' ');
+ }
+
+ nsCString pseudo;
+ if (mPseudoTag) {
+ nsAutoString pseudoTag;
+ mPseudoTag->ToString(pseudoTag);
+ AppendUTF16toUTF8(pseudoTag, pseudo);
+ pseudo.Append(' ');
+ }
+
+ nsCString flags;
+ if (IsStyleIfVisited()) {
+ flags.AppendLiteral("IS_STYLE_IF_VISITED ");
+ }
+ if (HasChildThatUsesGrandancestorStyle()) {
+ flags.AppendLiteral("CHILD_USES_GRANDANCESTOR_STYLE ");
+ }
+ if (IsShared()) {
+ flags.AppendLiteral("IS_SHARED ");
+ }
+
+ nsCString parent;
+ if (aFirst) {
+ parent.AppendPrintf("parent=%p ", mParent.get());
+ }
+
+ LOG_RESTYLE("%p(%d) %s%s%s%s",
+ this, mRefCnt,
+ structs.get(), pseudo.get(), flags.get(), parent.get());
+
+ LOG_RESTYLE_INDENT();
+
if (nullptr != mChild) {
GeckoStyleContext* child = mChild;
do {
child->LogStyleContextTree(false, aStructs);
child = child->mNextSibling;
} while (mChild != child);
}
if (nullptr != mEmptyChild) {
@@ -491,19 +564,83 @@ ShouldBlockifyChildren(const nsStyleDisp
return mozilla::StyleDisplay::Flex == displayVal ||
mozilla::StyleDisplay::InlineFlex == displayVal ||
mozilla::StyleDisplay::Grid == displayVal ||
mozilla::StyleDisplay::InlineGrid == displayVal;
}
#ifdef DEBUG
void
-GeckoStyleContext::AssertChildStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext,
- int32_t aLevels) const
+GeckoStyleContext::AssertStructsNotUsedElsewhere(
+ GeckoStyleContext* aDestroyingContext,
+ int32_t aLevels) const
{
+ if (aLevels == 0) {
+ return;
+ }
+
+ void* data;
+
+ if (mBits & NS_STYLE_IS_GOING_AWAY) {
+ return;
+ }
+
+ if (this != aDestroyingContext) {
+ nsInheritedStyleData& destroyingInheritedData =
+ aDestroyingContext->mCachedInheritedData;
+#define STYLE_STRUCT_INHERITED(name_, checkdata_cb) \
+ data = destroyingInheritedData.mStyleStructs[eStyleStruct_##name_]; \
+ if (data && \
+ !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
+ (mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] == data)) { \
+ printf_stderr("style struct %p found on style context %p\n", data, this);\
+ nsString url; \
+ nsresult rv = PresContext()->Document()->GetURL(url); \
+ if (NS_SUCCEEDED(rv)) { \
+ printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
+ } \
+ MOZ_ASSERT(false, "destroying " #name_ " style struct still present " \
+ "in style context tree"); \
+ }
+#define STYLE_STRUCT_RESET(name_, checkdata_cb)
+
+#include "nsStyleStructList.h"
+
+#undef STYLE_STRUCT_INHERITED
+#undef STYLE_STRUCT_RESET
+
+ if (mCachedResetData) {
+ nsResetStyleData* destroyingResetData =
+ aDestroyingContext->mCachedResetData;
+ if (destroyingResetData) {
+#define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)
+#define STYLE_STRUCT_RESET(name_, checkdata_cb) \
+ data = destroyingResetData->mStyleStructs[eStyleStruct_##name_]; \
+ if (data && \
+ !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
+ (mCachedResetData->mStyleStructs[eStyleStruct_##name_] == data)) { \
+ printf_stderr("style struct %p found on style context %p\n", data, \
+ this); \
+ nsString url; \
+ nsresult rv = PresContext()->Document()->GetURL(url); \
+ if (NS_SUCCEEDED(rv)) { \
+ printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
+ } \
+ MOZ_ASSERT(false, "destroying " #name_ " style struct still present "\
+ "in style context tree"); \
+ }
+
+#include "nsStyleStructList.h"
+
+#undef STYLE_STRUCT_INHERITED
+#undef STYLE_STRUCT_RESET
+ }
+ }
+ }
+
if (mChild) {
const GeckoStyleContext* child = mChild;
do {
child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
child = child->mNextSibling;
} while (child != mChild);
}
@@ -512,16 +649,17 @@ GeckoStyleContext::AssertChildStructsNot
do {
child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
child = child->mNextSibling;
} while (child != mEmptyChild);
}
}
#endif
+
void
GeckoStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup)
{
#define GET_UNIQUE_STYLE_DATA(name_) \
static_cast<nsStyle##name_*>(GetUniqueStyleData(eStyleStruct_##name_))
// CSS Inline Layout Level 3 - 3.5 Sizing Initial Letters:
// For an N-line drop initial in a Western script, the cap-height of the
@@ -809,8 +947,65 @@ GeckoStyleContext::StyleData(nsStyleStru
// always cache inherited data on the style context; the rule
// node set the bit in mBits for us if needed.
mCachedInheritedData.mStyleStructs[aSID] = const_cast<void*>(newData);
}
return newData;
}
+void
+GeckoStyleContext::DestroyCachedStructs(nsPresContext* aPresContext)
+{
+ mCachedInheritedData.DestroyStructs(mBits, aPresContext);
+ if (mCachedResetData) {
+ mCachedResetData->Destroy(mBits, aPresContext);
+ }
+}
+
+
+void
+GeckoStyleContext::SwapStyleData(GeckoStyleContext* aNewContext, uint32_t aStructs)
+{
+ static_assert(nsStyleStructID_Length <= 32, "aStructs is not big enough");
+
+ for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
+ i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
+ i = nsStyleStructID(i + 1)) {
+ uint32_t bit = nsCachedStyleData::GetBitForSID(i);
+ if (!(aStructs & bit)) {
+ continue;
+ }
+ void*& thisData = mCachedInheritedData.mStyleStructs[i];
+ void*& otherData = aNewContext->mCachedInheritedData.mStyleStructs[i];
+ if (mBits & bit) {
+ if (thisData == otherData) {
+ thisData = nullptr;
+ }
+ } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
+ std::swap(thisData, otherData);
+ }
+ }
+
+ for (nsStyleStructID i = nsStyleStructID_Reset_Start;
+ i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
+ i = nsStyleStructID(i + 1)) {
+ uint32_t bit = nsCachedStyleData::GetBitForSID(i);
+ if (!(aStructs & bit)) {
+ continue;
+ }
+ if (!mCachedResetData) {
+ mCachedResetData = new (PresContext()) nsResetStyleData;
+ }
+ if (!aNewContext->mCachedResetData) {
+ aNewContext->mCachedResetData = new (PresContext()) nsResetStyleData;
+ }
+ void*& thisData = mCachedResetData->mStyleStructs[i];
+ void*& otherData = aNewContext->mCachedResetData->mStyleStructs[i];
+ if (mBits & bit) {
+ if (thisData == otherData) {
+ thisData = nullptr;
+ }
+ } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
+ std::swap(thisData, otherData);
+ }
+ }
+}
--- a/layout/style/GeckoStyleContext.h
+++ b/layout/style/GeckoStyleContext.h
@@ -74,52 +74,119 @@ public:
*
* The typesafe functions below are preferred to the use of this
* function, both because they're easier to read and because they're
* faster.
*/
const void* NS_FASTCALL StyleData(nsStyleStructID aSID) MOZ_NONNULL_RETURN;
#ifdef DEBUG
- void AssertChildStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext,
- int32_t aLevels) const;
void ListDescendants(FILE* out, int32_t aIndent);
#endif
#ifdef RESTYLE_LOGGING
- void LogChildStyleContextTree(uint32_t aStructs) const;
+
+ // This only gets called under call trees where we've already checked
+ // that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
+ // It exists here just to satisfy LOG_RESTYLE's expectations.
+ bool ShouldLogRestyle() { return true; }
+ void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs);
+ void LogStyleContextTree(bool aFirst, uint32_t aStructs);
+ int32_t& LoggingDepth();
+ nsCString GetCachedStyleDataAsString(uint32_t aStructs);
#endif
// Only called for Gecko-backed nsStyleContexts.
void ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup);
bool HasNoChildren() const;
nsRuleNode* RuleNode() const {
MOZ_ASSERT(mRuleNode);
return mRuleNode;
}
~GeckoStyleContext() {
Destructor();
}
+ /**
+ * Swaps owned style struct pointers between this and aNewContext, on
+ * the assumption that aNewContext is the new style context for a frame
+ * and this is the old one. aStructs indicates which structs to consider
+ * swapping; only those which are owned in both this and aNewContext
+ * will be swapped.
+ *
+ * Additionally, if there are identical struct pointers for one of the
+ * structs indicated by aStructs, and it is not an owned struct on this,
+ * then the cached struct slot on this will be set to null. If the struct
+ * has been swapped on an ancestor, this style context (being the old one)
+ * will be left caching the struct pointer on the new ancestor, despite
+ * inheriting from the old ancestor. This is not normally a problem, as
+ * this style context will usually be destroyed by being released at the
+ * end of ElementRestyler::Restyle; but for style contexts held on to outside
+ * of the frame, we need to clear out the cached pointer so that if we need
+ * it again we'll re-fetch it from the new ancestor.
+ */
+ void SwapStyleData(GeckoStyleContext* aNewContext, uint32_t aStructs);
+
+ void DestroyCachedStructs(nsPresContext* aPresContext);
+
+ /**
+ * Return style data that is currently cached on the style context.
+ * Only returns the structs we cache ourselves; never consults the
+ * rule tree.
+ *
+ * For "internal" use only in nsStyleContext and nsRuleNode.
+ */
+ const void* GetCachedStyleData(nsStyleStructID aSID)
+ {
+ const void* cachedData;
+ if (nsCachedStyleData::IsReset(aSID)) {
+ if (mCachedResetData) {
+ cachedData = mCachedResetData->mStyleStructs[aSID];
+ } else {
+ cachedData = nullptr;
+ }
+ } else {
+ cachedData = mCachedInheritedData.mStyleStructs[aSID];
+ }
+ return cachedData;
+ }
+
+ // mCachedInheritedData and mCachedResetData point to both structs that
+ // are owned by this style context and structs that are owned by one of
+ // this style context's ancestors (which are indirectly owned since this
+ // style context owns a reference to its parent). If the bit in |mBits|
+ // is set for a struct, that means that the pointer for that struct is
+ // owned by an ancestor or by the rule node rather than by this style context.
+ // Since style contexts typically have some inherited data but only sometimes
+ // have reset data, we always allocate the mCachedInheritedData, but only
+ // sometimes allocate the mCachedResetData.
+ nsResetStyleData* mCachedResetData; // Cached reset style data.
+ nsInheritedStyleData mCachedInheritedData; // Cached inherited style data
+
+#ifdef DEBUG
+ void AssertStructsNotUsedElsewhere(GeckoStyleContext* aDestroyingContext,
+ int32_t aLevels) const;
+#endif
+
private:
// Helper for ClearCachedInheritedStyleDataOnDescendants.
void DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs);
// Children are kept in two circularly-linked lists. The list anchor
// is not part of the list (null for empty), and we point to the first
// child.
// mEmptyChild for children whose rule node is the root rule node, and
// mChild for other children. The order of children is not
// meaningful.
GeckoStyleContext* mChild;
GeckoStyleContext* mEmptyChild;
GeckoStyleContext* mPrevSibling;
GeckoStyleContext* mNextSibling;
RefPtr<nsRuleNode> mRuleNode;
+
};
-
}
#endif // mozilla_GeckoStyleContext_h
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -81,17 +81,16 @@ const uint32_t nsStyleContext::sDependen
static bool sExpensiveStyleStructAssertionsEnabled;
#endif
nsStyleContext::nsStyleContext(nsStyleContext* aParent,
nsIAtom* aPseudoTag,
CSSPseudoElementType aPseudoType)
: mParent(aParent)
, mPseudoTag(aPseudoTag)
- , mCachedResetData(nullptr)
, mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT)
, mRefCnt(0)
#ifdef DEBUG
, mFrameRefCnt(0)
, mComputingStruct(nsStyleStructID_None)
#endif
{}
@@ -127,147 +126,60 @@ nsStyleContext::FinishConstruction()
static_assert(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
"NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
#undef eStyleStruct_LastItem
}
void
nsStyleContext::Destructor()
{
+ GeckoStyleContext* gecko = GetAsGecko();
#ifdef DEBUG
- if (const GeckoStyleContext* gecko = GetAsGecko()) {
+ if (gecko) {
NS_ASSERTION(gecko->HasNoChildren(), "destructing context with children");
- }
- MOZ_ASSERT(!IsServo() || !mCachedResetData);
-
- if (IsServo()) {
- MOZ_ASSERT(!mCachedResetData,
- "Servo shouldn't cache reset structs in nsStyleContext");
- for (const auto* data : mCachedInheritedData.mStyleStructs) {
- MOZ_ASSERT(!data,
- "Servo shouldn't cache inherit structs in nsStyleContext");
+ if (sExpensiveStyleStructAssertionsEnabled) {
+ // Assert that the style structs we are about to destroy are not referenced
+ // anywhere else in the style context tree. These checks are expensive,
+ // which is why they are not enabled by default.
+ GeckoStyleContext* root = gecko;
+ while (root->GetParent()) {
+ root = root->GetParent();
+ }
+ root->AssertStructsNotUsedElsewhere(gecko,
+ std::numeric_limits<int32_t>::max());
+ } else {
+ // In DEBUG builds when the pref is not enabled, we perform a more limited
+ // check just of the children of this style context.
+ gecko->AssertStructsNotUsedElsewhere(gecko, 2);
}
}
-
- if (sExpensiveStyleStructAssertionsEnabled) {
- // Assert that the style structs we are about to destroy are not referenced
- // anywhere else in the style context tree. These checks are expensive,
- // which is why they are not enabled by default.
- nsStyleContext* root = this;
- while (root->mParent) {
- root = root->mParent;
- }
- root->AssertStructsNotUsedElsewhere(this,
- std::numeric_limits<int32_t>::max());
- } else {
- // In DEBUG builds when the pref is not enabled, we perform a more limited
- // check just of the children of this style context.
- AssertStructsNotUsedElsewhere(this, 2);
- }
#endif
nsPresContext *presContext = PresContext();
DebugOnly<nsStyleSet*> geckoStyleSet = presContext->PresShell()->StyleSet()->GetAsGecko();
NS_ASSERTION(!geckoStyleSet ||
geckoStyleSet->GetRuleTree() == AsGecko()->RuleNode()->RuleTree() ||
geckoStyleSet->IsInRuleTreeReconstruct(),
"destroying style context from old rule tree too late");
if (mParent) {
mParent->RemoveChild(this);
} else {
presContext->StyleSet()->RootStyleContextRemoved();
}
// Free up our data structs.
- mCachedInheritedData.DestroyStructs(mBits, presContext);
- if (mCachedResetData) {
- mCachedResetData->Destroy(mBits, presContext);
+ if (gecko) {
+ gecko->DestroyCachedStructs(presContext);
}
// Free any ImageValues we were holding on to for CSS variable values.
CSSVariableImageTable::RemoveAll(this);
}
-#ifdef DEBUG
-void
-nsStyleContext::AssertStructsNotUsedElsewhere(
- nsStyleContext* aDestroyingContext,
- int32_t aLevels) const
-{
- if (aLevels == 0) {
- return;
- }
-
- void* data;
-
- if (mBits & NS_STYLE_IS_GOING_AWAY) {
- return;
- }
-
- if (this != aDestroyingContext) {
- nsInheritedStyleData& destroyingInheritedData =
- aDestroyingContext->mCachedInheritedData;
-#define STYLE_STRUCT_INHERITED(name_, checkdata_cb) \
- data = destroyingInheritedData.mStyleStructs[eStyleStruct_##name_]; \
- if (data && \
- !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
- (mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] == data)) { \
- printf_stderr("style struct %p found on style context %p\n", data, this);\
- nsString url; \
- nsresult rv = PresContext()->Document()->GetURL(url); \
- if (NS_SUCCEEDED(rv)) { \
- printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
- } \
- MOZ_ASSERT(false, "destroying " #name_ " style struct still present " \
- "in style context tree"); \
- }
-#define STYLE_STRUCT_RESET(name_, checkdata_cb)
-
-#include "nsStyleStructList.h"
-
-#undef STYLE_STRUCT_INHERITED
-#undef STYLE_STRUCT_RESET
-
- if (mCachedResetData) {
- nsResetStyleData* destroyingResetData =
- aDestroyingContext->mCachedResetData;
- if (destroyingResetData) {
-#define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)
-#define STYLE_STRUCT_RESET(name_, checkdata_cb) \
- data = destroyingResetData->mStyleStructs[eStyleStruct_##name_]; \
- if (data && \
- !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
- (mCachedResetData->mStyleStructs[eStyleStruct_##name_] == data)) { \
- printf_stderr("style struct %p found on style context %p\n", data, \
- this); \
- nsString url; \
- nsresult rv = PresContext()->Document()->GetURL(url); \
- if (NS_SUCCEEDED(rv)) { \
- printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
- } \
- MOZ_ASSERT(false, "destroying " #name_ " style struct still present "\
- "in style context tree"); \
- }
-
-#include "nsStyleStructList.h"
-
-#undef STYLE_STRUCT_INHERITED
-#undef STYLE_STRUCT_RESET
- }
- }
- }
-
- if (const GeckoStyleContext* gecko = GetAsGecko()) {
- gecko->AssertChildStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
- }
-}
-#endif
-
-
void nsStyleContext::AddChild(nsStyleContext* aChild)
{
if (GeckoStyleContext* gecko = GetAsGecko()) {
gecko->AddChild(aChild->AsGecko());
}
}
void nsStyleContext::RemoveChild(nsStyleContext* aChild)
@@ -848,146 +760,16 @@ nsStyleContext::LookupStruct(const nsACS
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
else
return false;
return true;
}
#endif
-void
-nsStyleContext::SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs)
-{
- static_assert(nsStyleStructID_Length <= 32, "aStructs is not big enough");
-
- for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
- i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
- i = nsStyleStructID(i + 1)) {
- uint32_t bit = nsCachedStyleData::GetBitForSID(i);
- if (!(aStructs & bit)) {
- continue;
- }
- void*& thisData = mCachedInheritedData.mStyleStructs[i];
- void*& otherData = aNewContext->mCachedInheritedData.mStyleStructs[i];
- if (mBits & bit) {
- if (thisData == otherData) {
- thisData = nullptr;
- }
- } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
- std::swap(thisData, otherData);
- }
- }
-
- for (nsStyleStructID i = nsStyleStructID_Reset_Start;
- i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
- i = nsStyleStructID(i + 1)) {
- uint32_t bit = nsCachedStyleData::GetBitForSID(i);
- if (!(aStructs & bit)) {
- continue;
- }
- if (!mCachedResetData) {
- mCachedResetData = new (PresContext()) nsResetStyleData;
- }
- if (!aNewContext->mCachedResetData) {
- aNewContext->mCachedResetData = new (PresContext()) nsResetStyleData;
- }
- void*& thisData = mCachedResetData->mStyleStructs[i];
- void*& otherData = aNewContext->mCachedResetData->mStyleStructs[i];
- if (mBits & bit) {
- if (thisData == otherData) {
- thisData = nullptr;
- }
- } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
- std::swap(thisData, otherData);
- }
- }
-}
-
-#ifdef RESTYLE_LOGGING
-nsCString
-nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
-{
- nsCString structs;
- for (nsStyleStructID i = nsStyleStructID(0);
- i < nsStyleStructID_Length;
- i = nsStyleStructID(i + 1)) {
- if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
- const void* data = GetCachedStyleData(i);
- if (!structs.IsEmpty()) {
- structs.Append(' ');
- }
- structs.AppendPrintf("%s=%p", StructName(i), data);
- if (HasCachedDependentStyleData(i)) {
- structs.AppendLiteral("(dependent)");
- } else {
- structs.AppendLiteral("(owned)");
- }
- }
- }
- return structs;
-}
-
-int32_t&
-nsStyleContext::LoggingDepth()
-{
- static int32_t depth = 0;
- return depth;
-}
-
-void
-nsStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
-{
- LoggingDepth() = aLoggingDepth;
- LogStyleContextTree(true, aStructs);
-}
-
-void
-nsStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
-{
- nsCString structs = GetCachedStyleDataAsString(aStructs);
- if (!structs.IsEmpty()) {
- structs.Append(' ');
- }
-
- nsCString pseudo;
- if (mPseudoTag) {
- nsAutoString pseudoTag;
- mPseudoTag->ToString(pseudoTag);
- AppendUTF16toUTF8(pseudoTag, pseudo);
- pseudo.Append(' ');
- }
-
- nsCString flags;
- if (IsStyleIfVisited()) {
- flags.AppendLiteral("IS_STYLE_IF_VISITED ");
- }
- if (HasChildThatUsesGrandancestorStyle()) {
- flags.AppendLiteral("CHILD_USES_GRANDANCESTOR_STYLE ");
- }
- if (IsShared()) {
- flags.AppendLiteral("IS_SHARED ");
- }
-
- nsCString parent;
- if (aFirst) {
- parent.AppendPrintf("parent=%p ", mParent.get());
- }
-
- LOG_RESTYLE("%p(%d) %s%s%s%s",
- this, mRefCnt,
- structs.get(), pseudo.get(), flags.get(), parent.get());
-
- LOG_RESTYLE_INDENT();
-
- if (const GeckoStyleContext* gecko = GetAsGecko()) {
- gecko->LogChildStyleContextTree(aStructs);
- }
-}
-#endif
-
#ifdef DEBUG
/* static */ void
nsStyleContext::Initialize()
{
Preferences::AddBoolVarCache(
&sExpensiveStyleStructAssertionsEnabled,
"layout.css.expensive-style-struct-assertions.enabled");
}
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -379,70 +379,22 @@ public:
* Moves this style context to a new parent.
*
* This function violates style context tree immutability, and
* is a very low-level function and should only be used after verifying
* many conditions that make it safe to call.
*/
void MoveTo(nsStyleContext* aNewParent);
- /**
- * Swaps owned style struct pointers between this and aNewContext, on
- * the assumption that aNewContext is the new style context for a frame
- * and this is the old one. aStructs indicates which structs to consider
- * swapping; only those which are owned in both this and aNewContext
- * will be swapped.
- *
- * Additionally, if there are identical struct pointers for one of the
- * structs indicated by aStructs, and it is not an owned struct on this,
- * then the cached struct slot on this will be set to null. If the struct
- * has been swapped on an ancestor, this style context (being the old one)
- * will be left caching the struct pointer on the new ancestor, despite
- * inheriting from the old ancestor. This is not normally a problem, as
- * this style context will usually be destroyed by being released at the
- * end of ElementRestyler::Restyle; but for style contexts held on to outside
- * of the frame, we need to clear out the cached pointer so that if we need
- * it again we'll re-fetch it from the new ancestor.
- */
- void SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs);
-
#ifdef DEBUG
void List(FILE* out, int32_t aIndent, bool aListDescendants = true);
static const char* StructName(nsStyleStructID aSID);
static bool LookupStruct(const nsACString& aName, nsStyleStructID& aResult);
#endif
-#ifdef RESTYLE_LOGGING
- nsCString GetCachedStyleDataAsString(uint32_t aStructs);
- void LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs);
- int32_t& LoggingDepth();
-#endif
-
- /**
- * Return style data that is currently cached on the style context.
- * Only returns the structs we cache ourselves; never consults the
- * rule tree.
- *
- * For "internal" use only in nsStyleContext and nsRuleNode.
- */
- const void* GetCachedStyleData(nsStyleStructID aSID)
- {
- const void* cachedData;
- if (nsCachedStyleData::IsReset(aSID)) {
- if (mCachedResetData) {
- cachedData = mCachedResetData->mStyleStructs[aSID];
- } else {
- cachedData = nullptr;
- }
- } else {
- cachedData = mCachedInheritedData.mStyleStructs[aSID];
- }
- return cachedData;
- }
-
protected:
// protected destructor to discourage deletion outside of Release()
~nsStyleContext() {}
// Where the actual destructor lives
// We use this instead of a real destructor because we need
// this to be called *before* the subclass fields are destroyed
// by the subclass destructor
void Destructor();
@@ -509,53 +461,27 @@ protected:
#define STYLE_STRUCT_RESET(name_, checkdata_cb_) \
template<bool aComputeData> \
const nsStyle##name_ * DoGetStyle##name_();
#include "nsStyleStructList.h"
#undef STYLE_STRUCT_RESET
#undef STYLE_STRUCT_INHERITED
-#ifdef DEBUG
- void AssertStructsNotUsedElsewhere(nsStyleContext* aDestroyingContext,
- int32_t aLevels) const;
-#endif
-
-#ifdef RESTYLE_LOGGING
- void LogStyleContextTree(bool aFirst, uint32_t aStructs);
-
- // This only gets called under call trees where we've already checked
- // that PresContext()->RestyleManager()->ShouldLogRestyle() returned true.
- // It exists here just to satisfy LOG_RESTYLE's expectations.
- bool ShouldLogRestyle() { return true; }
-#endif
-
RefPtr<nsStyleContext> mParent;
// Style to be used instead for the R, G, and B components of color,
// background-color, and border-*-color if the nearest ancestor link
// element is visited (see RelevantLinkVisited()).
RefPtr<nsStyleContext> mStyleIfVisited;
// If this style context is for a pseudo-element or anonymous box,
// the relevant atom.
nsCOMPtr<nsIAtom> mPseudoTag;
- // mCachedInheritedData and mCachedResetData point to both structs that
- // are owned by this style context and structs that are owned by one of
- // this style context's ancestors (which are indirectly owned since this
- // style context owns a reference to its parent). If the bit in |mBits|
- // is set for a struct, that means that the pointer for that struct is
- // owned by an ancestor or by the rule node rather than by this style context.
- // Since style contexts typically have some inherited data but only sometimes
- // have reset data, we always allocate the mCachedInheritedData, but only
- // sometimes allocate the mCachedResetData.
- nsResetStyleData* mCachedResetData; // Cached reset style data.
- nsInheritedStyleData mCachedInheritedData; // Cached inherited style data
-
// mBits stores a number of things:
// - It records (using the style struct bits) which structs are
// inherited from the parent context or owned by the rule node (i.e.,
// not owned by the style context).
// - It also stores the additional bits listed at the top of
// nsStyleStruct.h.
uint64_t mBits;
--- a/layout/style/nsStyleContextInlines.h
+++ b/layout/style/nsStyleContextInlines.h
@@ -57,32 +57,34 @@ const nsStyle##name_ * nsStyleContext::P
// Helper functions for GetStyle* and PeekStyle*
#define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \
template<bool aComputeData> \
const nsStyle##name_ * nsStyleContext::DoGetStyle##name_() { \
if (auto gecko = GetAsGecko()) { \
const nsStyle##name_ * cachedData = \
static_cast<nsStyle##name_*>( \
- mCachedInheritedData.mStyleStructs[eStyleStruct_##name_]); \
+ gecko->mCachedInheritedData \
+ .mStyleStructs[eStyleStruct_##name_]); \
if (cachedData) /* Have it cached already, yay */ \
return cachedData; \
if (!aComputeData) { \
/* We always cache inherited structs on the context when we */\
/* compute them. */ \
return nullptr; \
} \
/* Have the rulenode deal */ \
AUTO_CHECK_DEPENDENCY(eStyleStruct_##name_); \
const nsStyle##name_ * newData = \
gecko->RuleNode()-> \
GetStyle##name_<aComputeData>(this->AsGecko(), mBits); \
/* always cache inherited data on the style context; the rule */\
/* node set the bit in mBits for us if needed. */ \
- mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] = \
+ gecko->mCachedInheritedData \
+ .mStyleStructs[eStyleStruct_##name_] = \
const_cast<nsStyle##name_ *>(newData); \
return newData; \
} \
auto servo = AsServo(); \
/** \
* Also (conservatively) set the owning bit in the parent style \
* context if we're a text node. \
* \
@@ -127,20 +129,20 @@ const nsStyle##name_ * nsStyleContext::D
} \
return data; \
}
#define STYLE_STRUCT_RESET(name_, checkdata_cb_) \
template<bool aComputeData> \
const nsStyle##name_ * nsStyleContext::DoGetStyle##name_() { \
if (auto gecko = GetAsGecko()) { \
- if (mCachedResetData) { \
+ if (gecko->mCachedResetData) { \
const nsStyle##name_ * cachedData = \
static_cast<nsStyle##name_*>( \
- mCachedResetData->mStyleStructs[eStyleStruct_##name_]); \
+ gecko->mCachedResetData->mStyleStructs[eStyleStruct_##name_]); \
if (cachedData) /* Have it cached already, yay */ \
return cachedData; \
} \
/* Have the rulenode deal */ \
AUTO_CHECK_DEPENDENCY(eStyleStruct_##name_); \
return gecko->RuleNode()->GetStyle##name_<aComputeData>(this->AsGecko()); \
} \
auto servo = AsServo(); \