Bug 979133 - Add facility to log the restyle process. r=dbaron

Set the MOZ_DEBUG_RESTYLE environment variable and every restyle will have
detailed logging printed to stderr. By default, restyles for animations are
not logged; you can include them by also setting MOZ_DEBUG_RESTYLE_ANIMATIONS.

If you wish to limit restyle logging to a particular change, you can call
nsPresContext::StartRestyleLogging() and nsPresContext::StopRestyleLogging()
at appropriate points. (You might want to add a couple of helper methods
temporarily on nsIDocument and then expose them to your page with Web IDL
to make them easier to call.) You do not need to have set MOZ_DEBUG_RESTYLE
for this to work.
This commit is contained in:
Cameron McCormack 2014-09-25 15:45:36 +10:00
Родитель 0770269478
Коммит f5e6faa47e
12 изменённых файлов: 521 добавлений и 18 удалений

Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/**
* Macros used to log restyle events.
*/
#ifndef mozilla_RestyleLogging_h
#define mozilla_RestyleLogging_h
#include "mozilla/AutoRestore.h"
#ifdef DEBUG
#define RESTYLE_LOGGING
#endif
#ifdef RESTYLE_LOGGING
#define LOG_RESTYLE_IF(object_, cond_, message_, ...) \
PR_BEGIN_MACRO \
if (object_->ShouldLogRestyle() && (cond_)) { \
nsCString line; \
for (int32_t restyle_depth_##__LINE__ = 0; \
restyle_depth_##__LINE__ < object_->LoggingDepth(); \
restyle_depth_##__LINE__++) { \
line.AppendLiteral(" "); \
} \
line.AppendPrintf(message_, ##__VA_ARGS__); \
printf_stderr("%s\n", line.get()); \
} \
PR_END_MACRO
#define LOG_RESTYLE(message_, ...) \
LOG_RESTYLE_IF(this, true, message_, ##__VA_ARGS__)
// Beware that LOG_RESTYLE_INDENT is two statements not wrapped in a block.
#define LOG_RESTYLE_INDENT() \
AutoRestore<int32_t> ar_depth_##__LINE__(LoggingDepth()); \
++LoggingDepth();
#else
#define LOG_RESTYLE_IF(cond_, message_, ...) /* nothing */
#define LOG_RESTYLE(message_, ...) /* nothing */
#define LOG_RESTYLE_INDENT() /* nothing */
#endif
#endif /* mozilla_RestyleLogging_h */

Просмотреть файл

@ -36,6 +36,7 @@
#include "nsIFrameInlines.h"
#include "ActiveLayerTracker.h"
#include "nsDisplayList.h"
#include "RestyleTrackerInlines.h"
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
@ -45,6 +46,19 @@ namespace mozilla {
using namespace layers;
#define LOG_RESTYLE_CONTINUE(reason_, ...) \
LOG_RESTYLE("continuing restyle since " reason_, ##__VA_ARGS__)
#ifdef RESTYLE_LOGGING
static nsCString
FrameTagToString(const nsIFrame* aFrame)
{
nsCString result;
aFrame->ListTag(result);
return result;
}
#endif
RestyleManager::RestyleManager(nsPresContext* aPresContext)
: mPresContext(aPresContext)
, mRebuildAllStyleData(false)
@ -60,6 +74,9 @@ RestyleManager::RestyleManager(nsPresContext* aPresContext)
ELEMENT_IS_POTENTIAL_RESTYLE_ROOT)
, mPendingAnimationRestyles(ELEMENT_HAS_PENDING_ANIMATION_RESTYLE |
ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT)
#ifdef RESTYLE_LOGGING
, mLoggingDepth(0)
#endif
{
mPendingRestyles.Init(this);
mPendingAnimationRestyles.Init(this);
@ -2257,6 +2274,9 @@ ElementRestyler::ElementRestyler(nsPresContext* aPresContext,
, mOurA11yNotification(eDontNotify)
, mVisibleKidsOfHiddenElement(aVisibleKidsOfHiddenElement)
#endif
#ifdef RESTYLE_LOGGING
, mLoggingDepth(aRestyleTracker.LoggingDepth() + 1)
#endif
{
}
@ -2284,6 +2304,9 @@ ElementRestyler::ElementRestyler(const ElementRestyler& aParentRestyler,
, mOurA11yNotification(eDontNotify)
, mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement)
#endif
#ifdef RESTYLE_LOGGING
, mLoggingDepth(aParentRestyler.mLoggingDepth + 1)
#endif
{
if (aConstructorFlags & FOR_OUT_OF_FLOW_CHILD) {
// Note that the out-of-flow may not be a geometric descendant of
@ -2325,6 +2348,9 @@ ElementRestyler::ElementRestyler(ParentContextFromChildFrame,
, mOurA11yNotification(eDontNotify)
, mVisibleKidsOfHiddenElement(aParentRestyler.mVisibleKidsOfHiddenElement)
#endif
#ifdef RESTYLE_LOGGING
, mLoggingDepth(aParentRestyler.mLoggingDepth + 1)
#endif
{
}
@ -2351,6 +2377,11 @@ ElementRestyler::CaptureChange(nsStyleContext* aOldContext,
(ourChange & nsChangeHint_NeedReflow),
"Reflow hint bits set without actually asking for a reflow");
LOG_RESTYLE("CaptureChange, ourChange = %s, aChangeToAssume = %s",
RestyleManager::ChangeHintToString(ourChange).get(),
RestyleManager::ChangeHintToString(aChangeToAssume).get());
LOG_RESTYLE_INDENT();
// nsChangeHint_UpdateEffects is inherited, but it can be set due to changes
// in inherited properties (fill and stroke). Avoid propagating it into
// text nodes.
@ -2362,11 +2393,17 @@ ElementRestyler::CaptureChange(nsStyleContext* aOldContext,
NS_UpdateHint(ourChange, aChangeToAssume);
if (NS_UpdateHint(mHintsHandled, ourChange)) {
if (!(ourChange & nsChangeHint_ReconstructFrame) || mContent) {
LOG_RESTYLE("appending change %s",
RestyleManager::ChangeHintToString(ourChange).get());
mChangeList->AppendChange(mFrame, mContent, ourChange);
} else {
LOG_RESTYLE("change has already been handled");
}
}
NS_UpdateHint(mHintsNotHandledForDescendants,
NS_HintsNotHandledForDescendantsIn(ourChange));
LOG_RESTYLE("mHintsNotHandledForDescendants = %s",
RestyleManager::ChangeHintToString(mHintsNotHandledForDescendants).get());
}
/**
@ -2500,6 +2537,8 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
// If we received eRestyleResult_Stop, then the old style context was
// left on mFrame. Since we ended up restyling our parent, change
// this old style context to point to its new parent.
LOG_RESTYLE("moving style context %p from old parent %p to new parent %p",
oldContext.get(), oldContext->GetParent(), newParent);
oldContext->MoveTo(newParent);
}
@ -2564,6 +2603,7 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
// have, so we don't considering stopping if this frame has any additional
// style contexts.
if (aSelf->GetAdditionalStyleContext(0)) {
LOG_RESTYLE_CONTINUE("there are additional style contexts");
return eRestyleResult_Continue;
}
@ -2573,7 +2613,14 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
// that they get the correct style context parent. Similarly for
// nsLineFrames.
nsIAtom* type = aSelf->GetType();
if (type == nsGkAtoms::letterFrame || type == nsGkAtoms::lineFrame) {
if (type == nsGkAtoms::letterFrame) {
LOG_RESTYLE_CONTINUE("frame is a letter frame");
return eRestyleResult_Continue;
}
if (type == nsGkAtoms::lineFrame) {
LOG_RESTYLE_CONTINUE("frame is a line frame");
return eRestyleResult_Continue;
}
@ -2586,16 +2633,19 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
// and we need to recompute the child's 'inherit' to that new value.
nsStyleContext* oldContext = aSelf->StyleContext();
if (oldContext->HasChildThatUsesGrandancestorStyle()) {
LOG_RESTYLE_CONTINUE("the old context uses grandancestor style");
return eRestyleResult_Continue;
}
// We ignore all situations that involve :visited style.
if (oldContext->GetStyleIfVisited()) {
LOG_RESTYLE_CONTINUE("the old style context has StyleIfVisited");
return eRestyleResult_Continue;
}
nsStyleContext* parentContext = oldContext->GetParent();
if (parentContext && parentContext->GetStyleIfVisited()) {
LOG_RESTYLE_CONTINUE("the old style context's parent has StyleIfVisited");
return eRestyleResult_Continue;
}
@ -2606,6 +2656,7 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
// pseudos.
nsIAtom* pseudoTag = oldContext->GetPseudo();
if (pseudoTag && pseudoTag != nsCSSAnonBoxes::mozNonElement) {
LOG_RESTYLE_CONTINUE("the old style context is for a pseudo");
return eRestyleResult_Continue;
}
@ -2617,6 +2668,7 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf)
// ancestor).
nsIAtom* parentPseudoTag = parent->StyleContext()->GetPseudo();
if (parentPseudoTag && parentPseudoTag != nsCSSAnonBoxes::mozNonElement) {
LOG_RESTYLE_CONTINUE("the old style context's parent is for a pseudo");
return eRestyleResult_Continue;
}
}
@ -2632,6 +2684,7 @@ ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
// that we can avoid the style context tree surgery having to deal to deal
// with visited styles.
if (aNewContext->GetStyleIfVisited()) {
LOG_RESTYLE_CONTINUE("the new style context has StyleIfVisited");
return eRestyleResult_Continue;
}
@ -2644,6 +2697,8 @@ ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
oldContext->GetPseudo() != aNewContext->GetPseudo() ||
oldContext->GetPseudoType() != aNewContext->GetPseudoType() ||
oldContext->RuleNode() != aNewContext->RuleNode()) {
LOG_RESTYLE_CONTINUE("the old and new style contexts have different link/"
"visited/pseudo/rulenodes");
return eRestyleResult_Continue;
}
@ -2652,9 +2707,16 @@ ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
// bits, then we must keep restyling so that those new bit values are
// propagated.
if (oldContext->HasTextDecorationLines() !=
aNewContext->HasTextDecorationLines() ||
oldContext->HasPseudoElementData() !=
aNewContext->HasTextDecorationLines()) {
LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_TEXT_DECORATION_LINES differs between old"
" and new style contexts");
return eRestyleResult_Continue;
}
if (oldContext->HasPseudoElementData() !=
aNewContext->HasPseudoElementData()) {
LOG_RESTYLE_CONTINUE("NS_STYLE_HAS_PSEUDO_ELEMENT_DATA differs between old"
" and new style contexts");
return eRestyleResult_Continue;
}
@ -2677,6 +2739,11 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
// We do need a reference to oldContext for the lifetime of this function, and it's possible
// that the frame has the last reference to it, so AddRef it here.
LOG_RESTYLE("RestyleSelf %s, aRestyleHint = %s",
FrameTagToString(aSelf).get(),
RestyleManager::RestyleHintToString(aRestyleHint).get());
LOG_RESTYLE_INDENT();
RestyleResult result;
if (aRestyleHint & eRestyle_ForceDescendants) {
@ -2717,6 +2784,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
"ancestor filter.");
// resolve the provider here (before aSelf below).
LOG_RESTYLE("resolving child provider frame");
// assumeDifferenceHint forces the parent's change to be also
// applied to this frame, no matter what
@ -2736,6 +2804,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
// Set |mResolvedChild| so we don't bother resolving the
// provider again.
mResolvedChild = providerFrame;
LOG_RESTYLE_CONTINUE("we had a provider frame");
// Continue restyling past the odd style context inheritance.
result = eRestyleResult_Continue;
}
@ -2756,6 +2825,8 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
aRestyleHint = (aRestyleHint & ~eRestyle_StyleAttribute) | eRestyle_Self;
}
LOG_RESTYLE("parentContext = %p", parentContext);
// do primary context
nsRefPtr<nsStyleContext> newContext;
nsIFrame *prevContinuation =
@ -2769,6 +2840,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
if (copyFromContinuation) {
// Just use the style context from the frame's previous
// continuation.
LOG_RESTYLE("using previous continuation's context");
newContext = prevContinuationContext;
}
else if (pseudoTag == nsCSSAnonBoxes::mozNonElement) {
@ -2784,6 +2856,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
Element* pseudoElement =
(pseudoElementContent && pseudoElementContent->IsElement())
? pseudoElementContent->AsElement() : nullptr;
LOG_RESTYLE("reparenting style context");
newContext =
styleSet->ReparentStyleContext(oldContext, parentContext, element,
pseudoElement);
@ -2793,6 +2866,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
// ReparentStyleContext that rebuilds the path in the rule tree
// rather than reusing the rule node, as we need to do during a
// rule tree reconstruct.
LOG_RESTYLE("resolving style with replacement");
newContext =
styleSet->ResolveStyleWithReplacement(element, parentContext, oldContext,
aRestyleHint);
@ -2870,12 +2944,20 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
// we can use FindChildWithRules to keep a lot of the old
// style contexts around. However, we need to start from the
// same root.
LOG_RESTYLE("restyling root and keeping old context");
LOG_RESTYLE_IF(this, result != eRestyleResult_Continue,
"continuing restyle since this is the root");
newContext = oldContext;
// Never consider stopping restyling at the root.
result = eRestyleResult_Continue;
}
}
LOG_RESTYLE("oldContext = %p, newContext = %p%s",
oldContext.get(), newContext.get(),
oldContext == newContext ? (const char*) " (same)" :
(const char*) "");
if (newContext != oldContext) {
if (result == eRestyleResult_Stop) {
if (oldContext->IsShared()) {
@ -2883,6 +2965,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
// eRestyleResult_Stop and patch its parent to point to the
// new parent style context, as that change might not be valid
// for the other frames sharing the style context.
LOG_RESTYLE_CONTINUE("the old style context is shared");
result = eRestyleResult_Continue;
} else {
// Look at some details of the new style context to see if it would
@ -2906,6 +2989,9 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
if (equalStructs != NS_STYLE_INHERIT_MASK) {
// At least one struct had different data in it, so we must
// continue restyling children.
LOG_RESTYLE_CONTINUE("there is different style data: %s",
RestyleManager::StructNamesToString(
~equalStructs & NS_STYLE_INHERIT_MASK).get());
result = eRestyleResult_Continue;
}
}
@ -2918,6 +3004,9 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
if (equalStructs != NS_STYLE_INHERIT_MASK) {
// At least one struct had different data in it, so we must
// continue restyling children.
LOG_RESTYLE_CONTINUE("there is different style data: %s",
RestyleManager::StructNamesToString(
~equalStructs & NS_STYLE_INHERIT_MASK).get());
result = eRestyleResult_Continue;
}
}
@ -2946,6 +3035,7 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
sid = nsStyleStructID(sid + 1)) {
if (oldContext->HasCachedInheritedStyleData(sid) &&
!oldContext->HasSameCachedStyleData(newContext, sid)) {
LOG_RESTYLE_CONTINUE("there are different struct pointers");
result = eRestyleResult_Continue;
break;
}
@ -2962,12 +3052,26 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
// previous continuation, so newContext == oldContext.
if (result != eRestyleResult_Stop) {
if (!oldContext->IsShared() && !newContext->IsShared()) {
if (oldContext->IsShared() && newContext->IsShared()) {
LOG_RESTYLE("not swapping style structs, since both old and contexts "
"are shared");
} else if (oldContext->IsShared()) {
LOG_RESTYLE("not swapping style structs, since the old context is "
"shared");
} else if (newContext->IsShared()) {
LOG_RESTYLE("not swapping style structs, since the new context is "
"shared");
} else {
LOG_RESTYLE("swapping style structs between %p and %p",
oldContext.get(), newContext.get());
oldContext->SwapStyleData(newContext, equalStructs);
*aSwappedStructs |= equalStructs;
}
LOG_RESTYLE("setting new style context");
aSelf->SetStyleContext(newContext);
}
} else {
LOG_RESTYLE("not setting new style context, since we'll reframe");
}
}
oldContext = nullptr;
@ -2979,6 +3083,8 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
for (nsStyleContext* oldExtraContext;
(oldExtraContext = aSelf->GetAdditionalStyleContext(contextIndex));
++contextIndex) {
LOG_RESTYLE("extra context %d", contextIndex);
LOG_RESTYLE_INDENT();
nsRefPtr<nsStyleContext> newExtraContext;
nsIAtom* const extraPseudoTag = oldExtraContext->GetPseudo();
const nsCSSPseudoElements::Type extraPseudoType =
@ -3024,16 +3130,23 @@ ElementRestyler::RestyleSelf(nsIFrame* aSelf,
MOZ_ASSERT(newExtraContext);
LOG_RESTYLE("newExtraContext = %p", newExtraContext.get());
if (oldExtraContext != newExtraContext) {
uint32_t equalStructs;
CaptureChange(oldExtraContext, newExtraContext, assumeDifferenceHint,
&equalStructs);
if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
LOG_RESTYLE("setting new extra style context");
aSelf->SetAdditionalStyleContext(contextIndex, newExtraContext);
} else {
LOG_RESTYLE("not setting new extra style context, since we'll reframe");
}
}
}
LOG_RESTYLE("returning %s", RestyleResultToString(result).get());
return result;
}
@ -3137,6 +3250,9 @@ ElementRestyler::RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint)
"Shouldn't have random pseudo style contexts in the "
"undisplayed map");
LOG_RESTYLE("RestyleUndisplayedChildren: undisplayed->mContent = %p",
undisplayed->mContent.get());
// Get the parent of the undisplayed content and check if it is a XBL
// children element. Push the children element as an ancestor here because it does
// not have a frame and would not otherwise be pushed as an ancestor.
@ -3218,6 +3334,8 @@ ElementRestyler::MaybeReframeForBeforePseudo()
nsCSSPseudoElements::ePseudo_before,
mPresContext)) {
// Have to create the new :before frame
LOG_RESTYLE("MaybeReframeForBeforePseudo, appending "
"nsChangeHint_ReconstructFrame");
NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame);
mChangeList->AppendChange(mFrame, mContent,
nsChangeHint_ReconstructFrame);
@ -3254,6 +3372,8 @@ ElementRestyler::MaybeReframeForAfterPseudo(nsIFrame* aFrame)
mPresContext) &&
!nsLayoutUtils::GetAfterFrame(aFrame)) {
// have to create the new :after frame
LOG_RESTYLE("MaybeReframeForAfterPseudo, appending "
"nsChangeHint_ReconstructFrame");
NS_UpdateHint(mHintsHandled, nsChangeHint_ReconstructFrame);
mChangeList->AppendChange(aFrame, mContent,
nsChangeHint_ReconstructFrame);
@ -3306,6 +3426,8 @@ void
ElementRestyler::RestyleContentChildren(nsIFrame* aParent,
nsRestyleHint aChildRestyleHint)
{
LOG_RESTYLE("RestyleContentChildren");
nsIFrame::ChildListIterator lists(aParent);
TreeMatchContext::AutoAncestorPusher ancestorPusher(mTreeMatchContext);
if (!lists.IsDone()) {
@ -3511,4 +3633,138 @@ RestyleManager::ComputeStyleChangeFor(nsIFrame* aFrame,
}
}
#ifdef DEBUG
/* static */ nsCString
RestyleManager::RestyleHintToString(nsRestyleHint aHint)
{
nsCString result;
bool any = false;
const char* names[] = { "Self", "Subtree", "LaterSiblings", "CSSTransitions",
"CSSAnimations", "SVGAttrAnimations", "StyleAttribute",
"ChangeAnimationPhase", "Force", "ForceDescendants" };
uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1);
uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1);
for (uint32_t i = 0; i < ArrayLength(names); i++) {
if (hint & (1 << i)) {
if (any) {
result.AppendLiteral(" | ");
}
result.AppendPrintf("eRestyle_%s", names[i]);
any = true;
}
}
if (rest) {
if (any) {
result.AppendLiteral(" | ");
}
result.AppendPrintf("0x%0x", rest);
} else {
if (!any) {
result.AppendLiteral("0");
}
}
return result;
}
/* static */ nsCString
RestyleManager::ChangeHintToString(nsChangeHint aHint)
{
nsCString result;
bool any = false;
const char* names[] = {
"RepaintFrame", "NeedReflow", "ClearAncestorIntrinsics",
"ClearDescendantIntrinsics", "NeedDirtyReflow", "SyncFrameView",
"UpdateCursor", "UpdateEffects", "UpdateOpacityLayer",
"UpdateTransformLayer", "ReconstructFrame", "UpdateOverflow",
"UpdateSubtreeOverflow", "UpdatePostTransformOverflow",
"ChildrenOnlyTransform", "RecomputePosition", "AddOrRemoveTransform",
"BorderStyleNoneChange", "UpdateTextPath", "NeutralChange"
};
uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1);
uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1);
if (hint == nsChangeHint_Hints_NotHandledForDescendants) {
result.AppendLiteral("nsChangeHint_Hints_NotHandledForDescendants");
hint = 0;
any = true;
} else {
if ((hint & NS_STYLE_HINT_FRAMECHANGE) == NS_STYLE_HINT_FRAMECHANGE) {
result.AppendLiteral("NS_STYLE_HINT_FRAMECHANGE");
hint = hint & ~NS_STYLE_HINT_FRAMECHANGE;
any = true;
} else if ((hint & NS_STYLE_HINT_REFLOW) == NS_STYLE_HINT_REFLOW) {
result.AppendLiteral("NS_STYLE_HINT_REFLOW");
hint = hint & ~NS_STYLE_HINT_REFLOW;
any = true;
} else if ((hint & nsChangeHint_AllReflowHints) == nsChangeHint_AllReflowHints) {
result.AppendLiteral("nsChangeHint_AllReflowHints");
hint = hint & ~nsChangeHint_AllReflowHints;
any = true;
} else if ((hint & NS_STYLE_HINT_VISUAL) == NS_STYLE_HINT_VISUAL) {
result.AppendLiteral("NS_STYLE_HINT_VISUAL");
hint = hint & ~NS_STYLE_HINT_VISUAL;
any = true;
}
}
for (uint32_t i = 0; i < ArrayLength(names); i++) {
if (hint & (1 << i)) {
if (any) {
result.AppendLiteral(" | ");
}
result.AppendPrintf("nsChangeHint_%s", names[i]);
any = true;
}
}
if (rest) {
if (any) {
result.AppendLiteral(" | ");
}
result.AppendPrintf("0x%0x", rest);
} else {
if (!any) {
result.AppendLiteral("NS_STYLE_HINT_NONE");
}
}
return result;
}
/* static */ nsCString
RestyleManager::StructNamesToString(uint32_t aSIDs)
{
nsCString result;
bool any = false;
for (nsStyleStructID sid = nsStyleStructID(0);
sid < nsStyleStructID_Length;
sid = nsStyleStructID(sid + 1)) {
if (aSIDs & nsCachedStyleData::GetBitForSID(sid)) {
if (any) {
result.AppendLiteral(",");
}
result.AppendPrintf("%s", nsStyleContext::StructName(sid));
any = true;
}
}
return result;
}
/* static */ nsCString
ElementRestyler::RestyleResultToString(RestyleResult aRestyleResult)
{
nsCString result;
switch (aRestyleResult) {
case eRestyleResult_Stop:
result.AssignLiteral("eRestyleResult_Stop");
break;
case eRestyleResult_Continue:
result.AssignLiteral("eRestyleResult_Continue");
break;
case eRestyleResult_ContinueAndForceDescendants:
result.AssignLiteral("eRestyleResult_ContinueAndForceDescendants");
break;
default:
result.AppendPrintf("RestyleResult(%d)", aRestyleResult);
}
return result;
}
#endif
} // namespace mozilla

Просмотреть файл

@ -11,6 +11,7 @@
#ifndef mozilla_RestyleManager_h
#define mozilla_RestyleManager_h
#include "mozilla/RestyleLogging.h"
#include "nsISupportsImpl.h"
#include "nsChangeHint.h"
#include "RestyleTracker.h"
@ -316,6 +317,11 @@ public:
mOverflowChangedTracker.Flush();
}
#ifdef DEBUG
static nsCString RestyleHintToString(nsRestyleHint aHint);
static nsCString ChangeHintToString(nsChangeHint aHint);
#endif
private:
/**
* Notify the frame constructor that an element needs to have its
@ -351,6 +357,39 @@ public:
*/
void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint);
#ifdef RESTYLE_LOGGING
/**
* Returns whether a restyle event currently being processed by this
* RestyleManager should be logged.
*/
bool ShouldLogRestyle() {
return ShouldLogRestyle(mPresContext);
}
/**
* Returns whether a restyle event currently being processed for the
* document with the specified nsPresContext should be logged.
*/
static bool ShouldLogRestyle(nsPresContext* aPresContext) {
return aPresContext->RestyleLoggingEnabled() &&
(!aPresContext->IsProcessingAnimationStyleChange() ||
AnimationRestyleLoggingEnabled());
}
static bool RestyleLoggingInitiallyEnabled() {
static bool enabled = getenv("MOZ_DEBUG_RESTYLE") != 0;
return enabled;
}
static bool AnimationRestyleLoggingEnabled() {
static bool animations = getenv("MOZ_DEBUG_RESTYLE_ANIMATIONS") != 0;
return animations;
}
static nsCString StructNamesToString(uint32_t aSIDs);
int32_t& LoggingDepth() { return mLoggingDepth; }
#endif
private:
/* aMinHint is the minimal change that should be made to the element */
// XXXbz do we really need the aPrimaryFrame argument here?
@ -393,6 +432,10 @@ private:
RestyleTracker mPendingRestyles;
RestyleTracker mPendingAnimationRestyles;
#ifdef RESTYLE_LOGGING
int32_t mLoggingDepth;
#endif
};
/**
@ -451,6 +494,12 @@ public:
*/
nsChangeHint HintsHandledForFrame() { return mHintsHandled; }
#ifdef RESTYLE_LOGGING
bool ShouldLogRestyle() {
return RestyleManager::ShouldLogRestyle(mPresContext);
}
#endif
private:
// Enum for the result of RestyleSelf, which indicates whether the
// restyle procedure should continue to the children, and how.
@ -517,6 +566,14 @@ private:
eNotifyHidden
};
#ifdef RESTYLE_LOGGING
int32_t& LoggingDepth() { return mLoggingDepth; }
#endif
#ifdef DEBUG
static nsCString RestyleResultToString(RestyleResult aRestyleResult);
#endif
private:
nsPresContext* const mPresContext;
nsIFrame* const mFrame;
@ -546,6 +603,10 @@ private:
nsTArray<nsIContent*>& mVisibleKidsOfHiddenElement;
bool mWasFrameVisible;
#endif
#ifdef RESTYLE_LOGGING
int32_t mLoggingDepth;
#endif
};
} // namespace mozilla

Просмотреть файл

@ -12,9 +12,38 @@
#include "nsStyleChangeList.h"
#include "RestyleManager.h"
#include "GeckoProfiler.h"
#include "nsIDocument.h"
#include "RestyleTrackerInlines.h"
namespace mozilla {
#ifdef RESTYLE_LOGGING
static nsCString
GetDocumentURI(nsIDocument* aDocument)
{
nsCString result;
nsString url;
aDocument->GetDocumentURI(url);
result.Append(NS_ConvertUTF16toUTF8(url).get());
return result;
}
static nsCString
FrameTagToString(dom::Element* aElement)
{
nsCString result;
nsIFrame* frame = aElement->GetPrimaryFrame();
if (frame) {
nsFrame::ListTag(result, frame);
} else {
nsAutoString buf;
aElement->Tag()->ToString(buf);
result.AppendPrintf("(%s@%p)", NS_ConvertUTF16toUTF8(buf).get(), aElement);
}
return result;
}
#endif
inline nsIDocument*
RestyleTracker::Document() const {
return mRestyleManager->PresContext()->Document();
@ -56,6 +85,9 @@ struct RestyleEnumerateData : RestyleTracker::Hints {
struct RestyleCollector {
RestyleTracker* tracker;
RestyleEnumerateData** restyleArrayPtr;
#ifdef RESTYLE_LOGGING
uint32_t count;
#endif
};
static PLDHashOperator
@ -73,6 +105,9 @@ CollectRestyles(nsISupports* aElement,
// document.
if (element->GetCrossShadowCurrentDoc() != collector->tracker->Document() ||
!element->HasFlag(collector->tracker->RestyleBit())) {
LOG_RESTYLE_IF(collector->tracker, true,
"skipping pending restyle %s, already restyled or no longer "
"in the document", FrameTagToString(element).get());
return PL_DHASH_NEXT;
}
@ -101,6 +136,10 @@ CollectRestyles(nsISupports* aElement,
currentRestyle->mRestyleHint = aData->mRestyleHint;
currentRestyle->mChangeHint = aData->mChangeHint;
#ifdef RESTYLE_LOGGING
collector->count++;
#endif
// Increment to the next slot in the array
*restyleArrayPtr = currentRestyle + 1;
@ -118,6 +157,10 @@ RestyleTracker::ProcessOneRestyle(Element* aElement,
NS_PRECONDITION(aElement->GetCrossShadowCurrentDoc() == Document(),
"Element has unexpected document");
LOG_RESTYLE("aRestyleHint = %s, aChangeHint = %s",
RestyleManager::RestyleHintToString(aRestyleHint).get(),
RestyleManager::ChangeHintToString(aChangeHint).get());
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
if (aRestyleHint & ~eRestyle_LaterSiblings) {
mRestyleManager->RestyleElement(aElement, primaryFrame, aChangeHint,
@ -140,6 +183,14 @@ RestyleTracker::DoProcessRestyles()
mRestyleManager->BeginProcessingRestyles();
LOG_RESTYLE("Processing %d pending %srestyles with %d restyle roots for %s",
mPendingRestyles.Count(),
mRestyleManager->PresContext()->IsProcessingAnimationStyleChange()
? (const char*) "animation " : (const char*) "",
static_cast<int>(mRestyleRoots.Length()),
GetDocumentURI(Document()).get());
LOG_RESTYLE_INDENT();
// loop so that we process any restyle events generated by processing
while (mPendingRestyles.Count()) {
if (mHaveLaterSiblingRestyles) {
@ -152,12 +203,17 @@ RestyleTracker::DoProcessRestyles()
for (nsIContent* sibling = element->GetNextSibling();
sibling;
sibling = sibling->GetNextSibling()) {
if (sibling->IsElement() &&
AddPendingRestyle(sibling->AsElement(), eRestyle_Subtree,
NS_STYLE_HINT_NONE)) {
// Nothing else to do here; we'll handle the following
// siblings when we get to |sibling| in laterSiblingArr.
break;
if (sibling->IsElement()) {
LOG_RESTYLE("adding pending restyle for %s due to "
"eRestyle_LaterSiblings hint on %s",
FrameTagToString(sibling->AsElement()).get(),
FrameTagToString(element->AsElement()).get());
if (AddPendingRestyle(sibling->AsElement(), eRestyle_Subtree,
NS_STYLE_HINT_NONE)) {
// Nothing else to do here; we'll handle the following
// siblings when we get to |sibling| in laterSiblingArr.
break;
}
}
}
}
@ -176,6 +232,9 @@ RestyleTracker::DoProcessRestyles()
nsRestyleHint(data->mRestyleHint & ~eRestyle_LaterSiblings);
}
LOG_RESTYLE("%d pending restyles after expanding out "
"eRestyle_LaterSiblings", mPendingRestyles.Count());
mHaveLaterSiblingRestyles = false;
}
@ -188,17 +247,23 @@ RestyleTracker::DoProcessRestyles()
element.swap(mRestyleRoots[rootCount - 1]);
mRestyleRoots.RemoveElementAt(rootCount - 1);
LOG_RESTYLE("processing style root %s at index %d",
FrameTagToString(element).get(), rootCount - 1);
LOG_RESTYLE_INDENT();
// Do the document check before calling GetRestyleData, since we
// don't want to do the sibling-processing GetRestyleData does if
// the node is no longer relevant.
if (element->GetCrossShadowCurrentDoc() != Document()) {
// Content node has been removed from our document; nothing else
// to do here
LOG_RESTYLE("skipping, no longer in the document");
continue;
}
nsAutoPtr<RestyleData> data;
if (!GetRestyleData(element, data)) {
LOG_RESTYLE("skipping, already restyled");
continue;
}
@ -227,9 +292,16 @@ RestyleTracker::DoProcessRestyles()
// Clear the hashtable now that we don't need it anymore
mPendingRestyles.Clear();
#ifdef RESTYLE_LOGGING
uint32_t index = 0;
#endif
for (RestyleEnumerateData* currentRestyle = restylesToProcess;
currentRestyle != lastRestyle;
++currentRestyle) {
LOG_RESTYLE("processing pending restyle %s at index %d/%d",
FrameTagToString(currentRestyle->mElement).get(),
index++, collector.count);
LOG_RESTYLE_INDENT();
ProcessOneRestyle(currentRestyle->mElement,
currentRestyle->mRestyleHint,
currentRestyle->mChangeHint);

Просмотреть файл

@ -15,6 +15,7 @@
#include "nsClassHashtable.h"
#include "nsContainerFrame.h"
#include "mozilla/SplayTree.h"
#include "mozilla/RestyleLogging.h"
namespace mozilla {
@ -233,9 +234,9 @@ public:
friend class ElementRestyler; // for AddPendingRestyleToTable
explicit RestyleTracker(Element::FlagsType aRestyleBits) :
mRestyleBits(aRestyleBits),
mHaveLaterSiblingRestyles(false)
explicit RestyleTracker(Element::FlagsType aRestyleBits)
: mRestyleBits(aRestyleBits)
, mHaveLaterSiblingRestyles(false)
{
NS_PRECONDITION((mRestyleBits & ~ELEMENT_ALL_RESTYLE_FLAGS) == 0,
"Why do we have these bits set?");
@ -342,6 +343,12 @@ public:
*/
inline nsIDocument* Document() const;
#ifdef RESTYLE_LOGGING
// Defined in RestyleTrackerInlines.h.
inline bool ShouldLogRestyle();
inline int32_t& LoggingDepth();
#endif
private:
bool AddPendingRestyleToTable(Element* aElement, nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint);

Просмотреть файл

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_RestyleTrackerInlines_h
#define mozilla_RestyleTrackerInlines_h
#ifdef RESTYLE_LOGGING
bool
mozilla::RestyleTracker::ShouldLogRestyle()
{
return mRestyleManager->ShouldLogRestyle();
}
int32_t&
mozilla::RestyleTracker::LoggingDepth()
{
return mRestyleManager->LoggingDepth();
}
#endif
#endif // !defined(mozilla_RestyleTrackerInlines_h)

Просмотреть файл

@ -59,6 +59,7 @@ EXPORTS += [
EXPORTS.mozilla += [
'GeometryUtils.h',
'PaintTracker.h',
'RestyleLogging.h',
]
UNIFIED_SOURCES += [

Просмотреть файл

@ -153,7 +153,8 @@ enum nsChangeHint {
nsChangeHint_NeutralChange = 0x100000
// IMPORTANT NOTE: When adding new hints, consider whether you need to
// add them to NS_HintsNotHandledForDescendantsIn() below.
// add them to NS_HintsNotHandledForDescendantsIn() below. Please also
// add them to RestyleManager::ChangeHintToString.
};
// Redefine these operators to return nothing. This will catch any use
@ -277,6 +278,9 @@ inline nsChangeHint NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint)
* Similarly, eRestyle_ForceDescendants will cause the frame and all of its
* descendants to be traversed and for the new style contexts that are created
* to be set on the frames.
*
* NOTE: When adding new restyle hints, please also add them to
* RestyleManager::RestyleHintToString.
*/
enum nsRestyleHint {
// Rerun selector matching on the element. If a new style context

Просмотреть файл

@ -1074,6 +1074,10 @@ nsPresContext::Init(nsDeviceContext* aDeviceContext)
mEventManager->SetPresContext(this);
#ifdef RESTYLE_LOGGING
mRestyleLoggingEnabled = RestyleManager::RestyleLoggingInitiallyEnabled();
#endif
#ifdef DEBUG
mInitialized = true;
#endif

Просмотреть файл

@ -37,6 +37,7 @@
#include "nsThreadUtils.h"
#include "ScrollbarStyles.h"
#include "nsIMessageManager.h"
#include "mozilla/RestyleLogging.h"
class nsBidiPresUtils;
class nsAString;
@ -1151,6 +1152,14 @@ public:
*/
bool MayHavePaintEventListenerInSubDocument();
#ifdef RESTYLE_LOGGING
// Controls for whether debug information about restyling in this
// document should be output.
bool RestyleLoggingEnabled() const { return mRestyleLoggingEnabled; }
void StartRestyleLogging() { mRestyleLoggingEnabled = true; }
void StopRestyleLogging() { mRestyleLoggingEnabled = false; }
#endif
protected:
void InvalidateThebesLayers();
void AppUnitsPerDevPixelChanged();
@ -1352,6 +1361,11 @@ protected:
unsigned mHasWarnedAboutPositionedTableParts : 1;
#ifdef RESTYLE_LOGGING
// Should we output debug information about restyling for this document?
bool mRestyleLoggingEnabled;
#endif
#ifdef DEBUG
bool mInitialized;
#endif

Просмотреть файл

@ -144,10 +144,10 @@ nsStyleContext::AssertStructsNotUsedElsewhere(
if (data && \
!(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
(mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] == data)) { \
printf("style struct %p found on style context %p\n", data, this); \
printf_stderr("style struct %p found on style context %p\n", data, this);\
nsString url; \
PresContext()->Document()->GetURL(url); \
printf(" in %s\n", NS_LossyConvertUTF16toASCII(url).get()); \
printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
MOZ_ASSERT(false, "destroying " #name_ " style struct still present " \
"in style context tree"); \
}
@ -168,10 +168,11 @@ nsStyleContext::AssertStructsNotUsedElsewhere(
if (data && \
!(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
(mCachedResetData->mStyleStructs[eStyleStruct_##name_] == data)) { \
printf("style struct %p found on style context %p\n", data, this); \
printf_stderr("style struct %p found on style context %p\n", data, \
this); \
nsString url; \
PresContext()->Document()->GetURL(url); \
printf(" in %s\n", NS_LossyConvertUTF16toASCII(url).get()); \
printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
MOZ_ASSERT(false, "destroying " #name_ " style struct still present "\
"in style context tree"); \
}
@ -1033,6 +1034,20 @@ nsStyleContext::AssertStyleStructMaxDifferenceValid()
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
}
/* static */ const char*
nsStyleContext::StructName(nsStyleStructID aSID)
{
switch (aSID) {
#define STYLE_STRUCT(name_, checkdata_cb) \
case eStyleStruct_##name_: \
return #name_;
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
default:
return "Unknown";
}
}
#endif
bool

Просмотреть файл

@ -396,6 +396,7 @@ public:
#ifdef DEBUG
void List(FILE* out, int32_t aIndent);
static void AssertStyleStructMaxDifferenceValid();
static const char* StructName(nsStyleStructID aSID);
#endif
private: