Bug 1072724 - Support showing more information about style structs in restyle logs. r=dbaron

The MOZ_DEBUG_RESTYLE_STRUCTS environment variable can be set to a comma-
separated list of style struct names.  When restyle logging is enabled,
this will cause the style context tree -- showing cached style struct
pointers for those structs specified -- to be logged before each
individual restyle is processed.  It will also show the struct pointer
values involved when swapping structs between style contexts.

For example, set MOZ_DEBUG_RESTYLE_STRUCTS=Font,UserInterface to show
the cached nsStyleFont and nsStyleUserInterface pointers on the style
contexts involved in the restyle process.
This commit is contained in:
Cameron McCormack 2014-10-01 09:13:57 +10:00
parent 30d276c56c
commit f449c11e35
5 changed files with 185 additions and 0 deletions

View File

@ -3069,6 +3069,16 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
oldContext.get(), newContext.get());
oldContext->SwapStyleData(newContext, equalStructs);
*aSwappedStructs |= equalStructs;
#ifdef RESTYLE_LOGGING
uint32_t structs = RestyleManager::StructsToLog() & equalStructs;
if (structs) {
LOG_RESTYLE_INDENT();
LOG_RESTYLE("old style context now has: %s",
oldContext->GetCachedStyleDataAsString(structs).get());
LOG_RESTYLE("new style context now has: %s",
newContext->GetCachedStyleDataAsString(structs).get());
}
#endif
}
LOG_RESTYLE("setting new style context");
aSelf->SetStyleContext(newContext);
@ -3636,6 +3646,39 @@ RestyleManager::ComputeStyleChangeFor(nsIFrame* aFrame,
}
}
#ifdef RESTYLE_LOGGING
uint32_t
RestyleManager::StructsToLog()
{
static bool initialized = false;
static uint32_t structs;
if (!initialized) {
structs = 0;
const char* value = getenv("MOZ_DEBUG_RESTYLE_STRUCTS");
if (value) {
nsCString s(value);
while (!s.IsEmpty()) {
int32_t index = s.FindChar(',');
nsStyleStructID sid;
bool found;
if (index == -1) {
found = nsStyleContext::LookupStruct(s, sid);
s.Truncate();
} else {
found = nsStyleContext::LookupStruct(Substring(s, 0, index), sid);
s = Substring(s, index + 1);
}
if (found) {
structs |= nsCachedStyleData::GetBitForSID(sid);
}
}
}
initialized = true;
}
return structs;
}
#endif
#ifdef DEBUG
/* static */ nsCString
RestyleManager::RestyleHintToString(nsRestyleHint aHint)

View File

@ -386,6 +386,13 @@ public:
return animations;
}
// Set MOZ_DEBUG_RESTYLE_STRUCTS to a comma-separated string of
// style struct names -- such as "Font,SVGReset" -- to log the style context
// tree and those cached struct pointers before each restyle. This
// function returns a bitfield of the structs named in the
// environment variable.
static uint32_t StructsToLog();
static nsCString StructNamesToString(uint32_t aSIDs);
int32_t& LoggingDepth() { return mLoggingDepth; }
#endif

View File

@ -162,7 +162,17 @@ RestyleTracker::ProcessOneRestyle(Element* aElement,
RestyleManager::ChangeHintToString(aChangeHint).get());
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
if (aRestyleHint & ~eRestyle_LaterSiblings) {
#ifdef RESTYLE_LOGGING
if (ShouldLogRestyle() && primaryFrame &&
RestyleManager::StructsToLog() != 0) {
LOG_RESTYLE("style context tree before restyle:");
LOG_RESTYLE_INDENT();
primaryFrame->StyleContext()->LogStyleContextTree(
LoggingDepth(), RestyleManager::StructsToLog());
}
#endif
mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
*this, aRestyleHint);
} else if (aChangeHint &&

View File

@ -1048,6 +1048,21 @@ nsStyleContext::StructName(nsStyleStructID aSID)
return "Unknown";
}
}
/* static */ bool
nsStyleContext::LookupStruct(const nsACString& aName, nsStyleStructID& aResult)
{
if (false)
;
#define STYLE_STRUCT(name_, checkdata_cb_) \
else if (aName.EqualsLiteral(#name_)) \
aResult = eStyleStruct_##name_;
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
else
return false;
return true;
}
#endif
bool
@ -1162,3 +1177,96 @@ nsStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
ClearCachedInheritedStyleDataOnDescendants(aStructs);
}
#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 (HasCachedInheritedStyleData(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 (UsesGrandancestorStyle()) {
flags.AppendLiteral("USES_GRANDANCESTOR_STYLE ");
}
if (IsShared()) {
flags.AppendLiteral("IS_SHARED ");
}
nsCString parent;
if (aFirst) {
parent.AppendPrintf("parent=%p ", mParent);
}
LOG_RESTYLE("%p(%d) %s%s%s%s",
this, mRefCnt,
structs.get(), pseudo.get(), flags.get(), parent.get());
LOG_RESTYLE_INDENT();
if (nullptr != mChild) {
nsStyleContext* child = mChild;
do {
child->LogStyleContextTree(false, aStructs);
child = child->mNextSibling;
} while (mChild != child);
}
if (nullptr != mEmptyChild) {
nsStyleContext* child = mEmptyChild;
do {
child->LogStyleContextTree(false, aStructs);
child = child->mNextSibling;
} while (mEmptyChild != child);
}
}
#endif

View File

@ -8,6 +8,7 @@
#ifndef _nsStyleContext_h_
#define _nsStyleContext_h_
#include "mozilla/RestyleLogging.h"
#include "nsRuleNode.h"
#include "nsCSSPseudoElements.h"
@ -397,6 +398,13 @@ public:
void List(FILE* out, int32_t aIndent);
static void AssertStyleStructMaxDifferenceValid();
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
private:
@ -450,6 +458,15 @@ private:
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
nsStyleContext* mParent; // STRONG
// Children are kept in two circularly-linked lists. The list anchor