Bug 931668 - Part 24: Avoid copying RestyleData::mDescendants when modifying an existing entry. r=dbaron

--HG--
extra : rebase_source : 0b9905bdff6f9ceec823b2091aadc39f0ca467bc
This commit is contained in:
Cameron McCormack 2014-09-05 13:48:48 +10:00
parent ba2eea0592
commit 01abd28246
3 changed files with 60 additions and 55 deletions

View File

@ -2420,14 +2420,14 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
// we'll fail to do the restyling we need to do. // we'll fail to do the restyling we need to do.
(mContent->GetParent() || mContent->GetPrimaryFrame() == mFrame)) { (mContent->GetParent() || mContent->GetPrimaryFrame() == mFrame)) {
mContent->OwnerDoc()->FlushPendingLinkUpdates(); mContent->OwnerDoc()->FlushPendingLinkUpdates();
RestyleTracker::RestyleData restyleData; nsAutoPtr<RestyleTracker::RestyleData> restyleData;
if (mRestyleTracker.GetRestyleData(mContent->AsElement(), &restyleData)) { if (mRestyleTracker.GetRestyleData(mContent->AsElement(), restyleData)) {
if (NS_UpdateHint(mHintsHandled, restyleData.mChangeHint)) { if (NS_UpdateHint(mHintsHandled, restyleData->mChangeHint)) {
mChangeList->AppendChange(mFrame, mContent, restyleData.mChangeHint); mChangeList->AppendChange(mFrame, mContent, restyleData->mChangeHint);
} }
hintToRestore = restyleData.mRestyleHint; hintToRestore = restyleData->mRestyleHint;
aRestyleHint = nsRestyleHint(aRestyleHint | restyleData.mRestyleHint); aRestyleHint = nsRestyleHint(aRestyleHint | restyleData->mRestyleHint);
descendants.SwapElements(restyleData.mDescendants); descendants.SwapElements(restyleData->mDescendants);
} }
} }
@ -3138,12 +3138,12 @@ ElementRestyler::RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint)
} }
nsRestyleHint thisChildHint = aChildRestyleHint; nsRestyleHint thisChildHint = aChildRestyleHint;
RestyleTracker::RestyleData undisplayedRestyleData; nsAutoPtr<RestyleTracker::RestyleData> undisplayedRestyleData;
Element* element = undisplayed->mContent->AsElement(); Element* element = undisplayed->mContent->AsElement();
if (mRestyleTracker.GetRestyleData(element, if (mRestyleTracker.GetRestyleData(element,
&undisplayedRestyleData)) { undisplayedRestyleData)) {
thisChildHint = thisChildHint =
nsRestyleHint(thisChildHint | undisplayedRestyleData.mRestyleHint); nsRestyleHint(thisChildHint | undisplayedRestyleData->mRestyleHint);
} }
nsRefPtr<nsStyleContext> undisplayedContext; nsRefPtr<nsStyleContext> undisplayedContext;
nsStyleSet* styleSet = mPresContext->StyleSet(); nsStyleSet* styleSet = mPresContext->StyleSet();

View File

@ -29,7 +29,7 @@ struct LaterSiblingCollector {
static PLDHashOperator static PLDHashOperator
CollectLaterSiblings(nsISupports* aElement, CollectLaterSiblings(nsISupports* aElement,
RestyleTracker::RestyleData& aData, nsAutoPtr<RestyleTracker::RestyleData>& aData,
void* aSiblingCollector) void* aSiblingCollector)
{ {
dom::Element* element = dom::Element* element =
@ -42,7 +42,7 @@ CollectLaterSiblings(nsISupports* aElement,
// document. // document.
if (element->GetCrossShadowCurrentDoc() == collector->tracker->Document() && if (element->GetCrossShadowCurrentDoc() == collector->tracker->Document() &&
element->HasFlag(collector->tracker->RestyleBit()) && element->HasFlag(collector->tracker->RestyleBit()) &&
(aData.mRestyleHint & eRestyle_LaterSiblings)) { (aData->mRestyleHint & eRestyle_LaterSiblings)) {
collector->elements->AppendElement(element); collector->elements->AppendElement(element);
} }
@ -56,7 +56,7 @@ struct RestyleCollector {
static PLDHashOperator static PLDHashOperator
CollectRestyles(nsISupports* aElement, CollectRestyles(nsISupports* aElement,
RestyleTracker::RestyleData& aData, nsAutoPtr<RestyleTracker::RestyleData>& aData,
void* aRestyleCollector) void* aRestyleCollector)
{ {
dom::Element* element = dom::Element* element =
@ -83,7 +83,7 @@ CollectRestyles(nsISupports* aElement,
// the bit, since any descendants that didn't get added // the bit, since any descendants that didn't get added
// to the roots list because we had the bits will be // to the roots list because we had the bits will be
// completely restyled in a moment. // completely restyled in a moment.
(aData.mChangeHint & nsChangeHint_ReconstructFrame), (aData->mChangeHint & nsChangeHint_ReconstructFrame),
"Why did this not get handled while processing mRestyleRoots?"); "Why did this not get handled while processing mRestyleRoots?");
// Unset the restyle bits now, so if they get readded later as we // Unset the restyle bits now, so if they get readded later as we
@ -96,8 +96,8 @@ CollectRestyles(nsISupports* aElement,
RestyleTracker::RestyleEnumerateData* currentRestyle = RestyleTracker::RestyleEnumerateData* currentRestyle =
*restyleArrayPtr; *restyleArrayPtr;
currentRestyle->mElement = element; currentRestyle->mElement = element;
currentRestyle->mRestyleHint = aData.mRestyleHint; currentRestyle->mRestyleHint = aData->mRestyleHint;
currentRestyle->mChangeHint = aData.mChangeHint; currentRestyle->mChangeHint = aData->mChangeHint;
// Increment to the next slot in the array // Increment to the next slot in the array
*restyleArrayPtr = currentRestyle + 1; *restyleArrayPtr = currentRestyle + 1;
@ -164,16 +164,14 @@ RestyleTracker::DoProcessRestyles()
for (uint32_t i = 0; i < laterSiblingArr.Length(); ++i) { for (uint32_t i = 0; i < laterSiblingArr.Length(); ++i) {
Element* element = laterSiblingArr[i]; Element* element = laterSiblingArr[i];
NS_ASSERTION(element->HasFlag(RestyleBit()), "How did that happen?"); NS_ASSERTION(element->HasFlag(RestyleBit()), "How did that happen?");
RestyleData data; RestyleData* data;
#ifdef DEBUG #ifdef DEBUG
bool found = bool found =
#endif #endif
mPendingRestyles.Get(element, &data); mPendingRestyles.Get(element, &data);
NS_ASSERTION(found, "Where did our entry go?"); NS_ASSERTION(found, "Where did our entry go?");
data.mRestyleHint = data->mRestyleHint =
nsRestyleHint(data.mRestyleHint & ~eRestyle_LaterSiblings); nsRestyleHint(data->mRestyleHint & ~eRestyle_LaterSiblings);
mPendingRestyles.Put(element, data);
} }
mHaveLaterSiblingRestyles = false; mHaveLaterSiblingRestyles = false;
@ -197,13 +195,13 @@ RestyleTracker::DoProcessRestyles()
continue; continue;
} }
RestyleData data; nsAutoPtr<RestyleData> data;
if (!GetRestyleData(element, &data)) { if (!GetRestyleData(element, data)) {
continue; continue;
} }
ProcessOneRestyle(element, data.mRestyleHint, data.mChangeHint); ProcessOneRestyle(element, data->mRestyleHint, data->mChangeHint);
AddRestyleRootsIfAwaitingRestyle(data.mDescendants); AddRestyleRootsIfAwaitingRestyle(data->mDescendants);
} }
if (mHaveLaterSiblingRestyles) { if (mHaveLaterSiblingRestyles) {
@ -243,7 +241,7 @@ RestyleTracker::DoProcessRestyles()
} }
bool bool
RestyleTracker::GetRestyleData(Element* aElement, RestyleData* aData) RestyleTracker::GetRestyleData(Element* aElement, nsAutoPtr<RestyleData>& aData)
{ {
NS_PRECONDITION(aElement->GetCrossShadowCurrentDoc() == Document(), NS_PRECONDITION(aElement->GetCrossShadowCurrentDoc() == Document(),
"Unexpected document; this will lead to incorrect behavior!"); "Unexpected document; this will lead to incorrect behavior!");
@ -253,11 +251,8 @@ RestyleTracker::GetRestyleData(Element* aElement, RestyleData* aData)
return false; return false;
} }
#ifdef DEBUG mPendingRestyles.RemoveAndForget(aElement, aData);
bool gotData = NS_ASSERTION(aData.get(), "Must have data if restyle bit is set");
#endif
mPendingRestyles.Get(aElement, aData);
NS_ASSERTION(gotData, "Must have data if restyle bit is set");
if (aData->mRestyleHint & eRestyle_LaterSiblings) { if (aData->mRestyleHint & eRestyle_LaterSiblings) {
// Someone readded the eRestyle_LaterSiblings hint for this // Someone readded the eRestyle_LaterSiblings hint for this
@ -266,15 +261,14 @@ RestyleTracker::GetRestyleData(Element* aElement, RestyleData* aData)
// since it's no longer a root with the new restyle data. // since it's no longer a root with the new restyle data.
NS_ASSERTION(aData->mDescendants.IsEmpty(), NS_ASSERTION(aData->mDescendants.IsEmpty(),
"expected descendants to be handled by now"); "expected descendants to be handled by now");
RestyleData newData; RestyleData* newData = new RestyleData;
newData.mChangeHint = nsChangeHint(0); newData->mChangeHint = nsChangeHint(0);
newData.mRestyleHint = eRestyle_LaterSiblings; newData->mRestyleHint = eRestyle_LaterSiblings;
mPendingRestyles.Put(aElement, newData); mPendingRestyles.Put(aElement, newData);
aElement->UnsetFlags(RootBit()); aElement->UnsetFlags(RootBit());
aData->mRestyleHint = aData->mRestyleHint =
nsRestyleHint(aData->mRestyleHint & ~eRestyle_LaterSiblings); nsRestyleHint(aData->mRestyleHint & ~eRestyle_LaterSiblings);
} else { } else {
mPendingRestyles.Remove(aElement);
aElement->UnsetFlags(mRestyleBits); aElement->UnsetFlags(mRestyleBits);
} }

View File

@ -12,7 +12,7 @@
#define mozilla_RestyleTracker_h #define mozilla_RestyleTracker_h
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "nsDataHashtable.h" #include "nsClassHashtable.h"
#include "nsContainerFrame.h" #include "nsContainerFrame.h"
#include "mozilla/SplayTree.h" #include "mozilla/SplayTree.h"
@ -286,8 +286,18 @@ public:
Element::FlagsType RootBit() const { Element::FlagsType RootBit() const {
return mRestyleBits & ~ELEMENT_PENDING_RESTYLE_FLAGS; return mRestyleBits & ~ELEMENT_PENDING_RESTYLE_FLAGS;
} }
struct RestyleData { struct RestyleData {
RestyleData() {
mRestyleHint = nsRestyleHint(0);
mChangeHint = NS_STYLE_HINT_NONE;
}
RestyleData(nsRestyleHint aRestyleHint, nsChangeHint aChangeHint) {
mRestyleHint = aRestyleHint;
mChangeHint = aChangeHint;
}
nsRestyleHint mRestyleHint; // What we want to restyle nsRestyleHint mRestyleHint; // What we want to restyle
nsChangeHint mChangeHint; // The minimal change hint for "self" nsChangeHint mChangeHint; // The minimal change hint for "self"
@ -306,10 +316,9 @@ public:
* eRestyle_LaterSiblings hint in it. * eRestyle_LaterSiblings hint in it.
* *
* The return value indicates whether any restyle data was found for * The return value indicates whether any restyle data was found for
* the element. If false is returned, then the state of *aData is * the element. aData is set to nullptr iff false is returned.
* undefined.
*/ */
bool GetRestyleData(Element* aElement, RestyleData* aData); bool GetRestyleData(Element* aElement, nsAutoPtr<RestyleData>& aData);
/** /**
* For each element in aElements, appends it to mRestyleRoots if it * For each element in aElements, appends it to mRestyleRoots if it
@ -353,14 +362,14 @@ private:
*/ */
void DoProcessRestyles(); void DoProcessRestyles();
typedef nsDataHashtable<nsISupportsHashKey, RestyleData> PendingRestyleTable; typedef nsClassHashtable<nsISupportsHashKey, RestyleData> PendingRestyleTable;
typedef nsAutoTArray< nsRefPtr<Element>, 32> RestyleRootArray; typedef nsAutoTArray< nsRefPtr<Element>, 32> RestyleRootArray;
// Our restyle bits. These will be a subset of ELEMENT_ALL_RESTYLE_FLAGS, and // Our restyle bits. These will be a subset of ELEMENT_ALL_RESTYLE_FLAGS, and
// will include one flag from ELEMENT_PENDING_RESTYLE_FLAGS and one flag // will include one flag from ELEMENT_PENDING_RESTYLE_FLAGS and one flag
// that's not in ELEMENT_PENDING_RESTYLE_FLAGS. // that's not in ELEMENT_PENDING_RESTYLE_FLAGS.
Element::FlagsType mRestyleBits; Element::FlagsType mRestyleBits;
RestyleManager* mRestyleManager; // Owns us RestyleManager* mRestyleManager; // Owns us
// A hashtable that maps elements to RestyleData structs. The // A hashtable that maps elements to pointers to RestyleData structs. The
// values only make sense if the element's current document is our // values only make sense if the element's current document is our
// document and it has our RestyleBit() flag set. In particular, // document and it has our RestyleBit() flag set. In particular,
// said bit might not be set if the element had a restyle posted and // said bit might not be set if the element had a restyle posted and
@ -384,9 +393,7 @@ RestyleTracker::AddPendingRestyleToTable(Element* aElement,
nsRestyleHint aRestyleHint, nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint) nsChangeHint aMinChangeHint)
{ {
RestyleData existingData; RestyleData* existingData;
existingData.mRestyleHint = nsRestyleHint(0);
existingData.mChangeHint = NS_STYLE_HINT_NONE;
// Check the RestyleBit() flag before doing the hashtable Get, since // Check the RestyleBit() flag before doing the hashtable Get, since
// it's possible that the data in the hashtable isn't actually // it's possible that the data in the hashtable isn't actually
@ -395,15 +402,20 @@ RestyleTracker::AddPendingRestyleToTable(Element* aElement,
mPendingRestyles.Get(aElement, &existingData); mPendingRestyles.Get(aElement, &existingData);
} else { } else {
aElement->SetFlags(RestyleBit()); aElement->SetFlags(RestyleBit());
existingData = nullptr;
}
if (!existingData) {
mPendingRestyles.Put(aElement,
new RestyleData(aRestyleHint, aMinChangeHint));
return false;
} }
bool hadRestyleLaterSiblings = bool hadRestyleLaterSiblings =
(existingData.mRestyleHint & eRestyle_LaterSiblings) != 0; (existingData->mRestyleHint & eRestyle_LaterSiblings) != 0;
existingData.mRestyleHint = existingData->mRestyleHint =
nsRestyleHint(existingData.mRestyleHint | aRestyleHint); nsRestyleHint(existingData->mRestyleHint | aRestyleHint);
NS_UpdateHint(existingData.mChangeHint, aMinChangeHint); NS_UpdateHint(existingData->mChangeHint, aMinChangeHint);
mPendingRestyles.Put(aElement, existingData);
return hadRestyleLaterSiblings; return hadRestyleLaterSiblings;
} }
@ -459,11 +471,10 @@ RestyleTracker::AddPendingRestyle(Element* aElement,
// invariant that if two elements appear in the array and one // invariant that if two elements appear in the array and one
// is an ancestor of the other, that the ancestor appears after // is an ancestor of the other, that the ancestor appears after
// the descendant. // the descendant.
RestyleData curData; RestyleData* curData;
// XXX We should avoid copying RestyleData::mDescendants around.
mPendingRestyles.Get(cur, &curData); mPendingRestyles.Get(cur, &curData);
curData.mDescendants.AppendElement(aElement); NS_ASSERTION(curData, "expected to find a RestyleData for cur");
mPendingRestyles.Put(cur, curData); curData->mDescendants.AppendElement(aElement);
} }
} }