зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 8e006947db44 (bug 1186780)
This commit is contained in:
Родитель
51adbe4deb
Коммит
d9c1315ad6
|
@ -336,55 +336,86 @@ const nsIID nsIStyleRule::COMTypeInfo<css::Rule, void>::kIID = NS_ISTYLE_RULE_II
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static PLDHashOperator
|
||||
CustomDefinitionsTraverse(CustomElementHashKey* aKey,
|
||||
CustomElementDefinition* aDefinition,
|
||||
void* aArg)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback* cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aArg);
|
||||
|
||||
nsAutoPtr<LifecycleCallbacks>& callbacks = aDefinition->mCallbacks;
|
||||
|
||||
if (callbacks->mAttributeChangedCallback.WasPassed()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
|
||||
cb->NoteXPCOMChild(aDefinition->mCallbacks->mAttributeChangedCallback.Value());
|
||||
}
|
||||
|
||||
if (callbacks->mCreatedCallback.WasPassed()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mCustomDefinitions->mCallbacks->mCreatedCallback");
|
||||
cb->NoteXPCOMChild(aDefinition->mCallbacks->mCreatedCallback.Value());
|
||||
}
|
||||
|
||||
if (callbacks->mAttachedCallback.WasPassed()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mCustomDefinitions->mCallbacks->mAttachedCallback");
|
||||
cb->NoteXPCOMChild(aDefinition->mCallbacks->mAttachedCallback.Value());
|
||||
}
|
||||
|
||||
if (callbacks->mDetachedCallback.WasPassed()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mCustomDefinitions->mCallbacks->mDetachedCallback");
|
||||
cb->NoteXPCOMChild(aDefinition->mCallbacks->mDetachedCallback.Value());
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
CandidatesTraverse(CustomElementHashKey* aKey,
|
||||
nsTArray<nsRefPtr<Element>>* aData,
|
||||
void* aArg)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aArg);
|
||||
for (size_t i = 0; i < aData->Length(); ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mCandidatesMap->Element");
|
||||
cb->NoteXPCOMChild(aData->ElementAt(i));
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
struct CustomDefinitionTraceArgs
|
||||
{
|
||||
const TraceCallbacks& callbacks;
|
||||
void* closure;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
CustomDefinitionTrace(CustomElementHashKey *aKey,
|
||||
CustomElementDefinition *aData,
|
||||
void *aArg)
|
||||
{
|
||||
CustomDefinitionTraceArgs* traceArgs = static_cast<CustomDefinitionTraceArgs*>(aArg);
|
||||
MOZ_ASSERT(aData, "Definition must not be null");
|
||||
traceArgs->callbacks.Trace(&aData->mPrototype, "mCustomDefinitions prototype",
|
||||
traceArgs->closure);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(Registry)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Registry)
|
||||
for (auto iter = tmp->mCustomDefinitions.ConstIter(); !iter.Done();
|
||||
iter.Next()) {
|
||||
aCallbacks.Trace(&iter.UserData()->mPrototype,
|
||||
"mCustomDefinitions prototype",
|
||||
aClosure);
|
||||
}
|
||||
CustomDefinitionTraceArgs customDefinitionArgs = { aCallbacks, aClosure };
|
||||
tmp->mCustomDefinitions.EnumerateRead(CustomDefinitionTrace,
|
||||
&customDefinitionArgs);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Registry)
|
||||
for (auto iter = tmp->mCustomDefinitions.ConstIter(); !iter.Done();
|
||||
iter.Next()) {
|
||||
CustomElementDefinition* definition = iter.UserData();
|
||||
auto callbacks = definition->mCallbacks;
|
||||
|
||||
if (callbacks->mAttributeChangedCallback.WasPassed()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||
"mCustomDefinitions->mCallbacks->mAttributeChangedCallback");
|
||||
cb.NoteXPCOMChild(callbacks->mAttributeChangedCallback.Value());
|
||||
}
|
||||
|
||||
if (callbacks->mCreatedCallback.WasPassed()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||
"mCustomDefinitions->mCallbacks->mCreatedCallback");
|
||||
cb.NoteXPCOMChild(callbacks->mCreatedCallback.Value());
|
||||
}
|
||||
|
||||
if (callbacks->mAttachedCallback.WasPassed()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||
"mCustomDefinitions->mCallbacks->mAttachedCallback");
|
||||
cb.NoteXPCOMChild(callbacks->mAttachedCallback.Value());
|
||||
}
|
||||
|
||||
if (callbacks->mDetachedCallback.WasPassed()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
|
||||
"mCustomDefinitions->mCallbacks->mDetachedCallback");
|
||||
cb.NoteXPCOMChild(callbacks->mDetachedCallback.Value());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto iter = tmp->mCandidatesMap.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto data = iter.UserData();
|
||||
for (size_t i = 0; i < data->Length(); ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCandidatesMap->Element");
|
||||
cb.NoteXPCOMChild(data->ElementAt(i));
|
||||
}
|
||||
}
|
||||
tmp->mCustomDefinitions.EnumerateRead(CustomDefinitionsTraverse, &cb);
|
||||
tmp->mCandidatesMap.EnumerateRead(CandidatesTraverse, &cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
|
@ -911,60 +942,99 @@ nsExternalResourceMap::RequestResource(nsIURI* aURI,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
struct
|
||||
nsExternalResourceEnumArgs
|
||||
{
|
||||
nsIDocument::nsSubDocEnumFunc callback;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static PLDHashOperator
|
||||
ExternalResourceEnumerator(nsIURI* aKey,
|
||||
nsExternalResourceMap::ExternalResource* aData,
|
||||
void* aClosure)
|
||||
{
|
||||
nsExternalResourceEnumArgs* args =
|
||||
static_cast<nsExternalResourceEnumArgs*>(aClosure);
|
||||
bool next =
|
||||
aData->mDocument ? args->callback(aData->mDocument, args->data) : true;
|
||||
return next ? PL_DHASH_NEXT : PL_DHASH_STOP;
|
||||
}
|
||||
|
||||
void
|
||||
nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback,
|
||||
void* aData)
|
||||
{
|
||||
for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto data = iter.UserData();
|
||||
if (data->mDocument && !aCallback(data->mDocument, aData)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
nsExternalResourceEnumArgs args = { aCallback, aData };
|
||||
mMap.EnumerateRead(ExternalResourceEnumerator, &args);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
ExternalResourceTraverser(nsIURI* aKey,
|
||||
nsExternalResourceMap::ExternalResource* aData,
|
||||
void* aClosure)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mExternalResourceMap.mMap entry"
|
||||
"->mDocument");
|
||||
cb->NoteXPCOMChild(aData->mDocument);
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mExternalResourceMap.mMap entry"
|
||||
"->mViewer");
|
||||
cb->NoteXPCOMChild(aData->mViewer);
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mExternalResourceMap.mMap entry"
|
||||
"->mLoadGroup");
|
||||
cb->NoteXPCOMChild(aData->mLoadGroup);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* cb) const
|
||||
nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) const
|
||||
{
|
||||
// mPendingLoads will get cleared out as the requests complete, so
|
||||
// no need to worry about those here.
|
||||
for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto data = iter.UserData();
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mExternalResourceMap.mMap entry"
|
||||
"->mDocument");
|
||||
cb->NoteXPCOMChild(data->mDocument);
|
||||
mMap.EnumerateRead(ExternalResourceTraverser, aCallback);
|
||||
}
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mExternalResourceMap.mMap entry"
|
||||
"->mViewer");
|
||||
cb->NoteXPCOMChild(data->mViewer);
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
||||
"mExternalResourceMap.mMap entry"
|
||||
"->mLoadGroup");
|
||||
cb->NoteXPCOMChild(data->mLoadGroup);
|
||||
static PLDHashOperator
|
||||
ExternalResourceHider(nsIURI* aKey,
|
||||
nsExternalResourceMap::ExternalResource* aData,
|
||||
void* aClosure)
|
||||
{
|
||||
if (aData->mViewer) {
|
||||
aData->mViewer->Hide();
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsExternalResourceMap::HideViewers()
|
||||
{
|
||||
for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
if (auto viewer = iter.UserData()->mViewer) {
|
||||
viewer->Hide();
|
||||
}
|
||||
mMap.EnumerateRead(ExternalResourceHider, nullptr);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
ExternalResourceShower(nsIURI* aKey,
|
||||
nsExternalResourceMap::ExternalResource* aData,
|
||||
void* aClosure)
|
||||
{
|
||||
if (aData->mViewer) {
|
||||
aData->mViewer->Show();
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsExternalResourceMap::ShowViewers()
|
||||
{
|
||||
for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
if (auto viewer = iter.UserData()->mViewer) {
|
||||
viewer->Show();
|
||||
}
|
||||
}
|
||||
mMap.EnumerateRead(ExternalResourceShower, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1533,6 +1603,15 @@ nsDocument::nsDocument(const char* aContentType)
|
|||
}
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
ClearAllBoxObjects(nsIContent* aKey, nsPIBoxObject* aBoxObject, void* aUserArg)
|
||||
{
|
||||
if (aBoxObject) {
|
||||
aBoxObject->Clear();
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsIDocument::~nsIDocument()
|
||||
{
|
||||
MOZ_ASSERT(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists),
|
||||
|
@ -1673,7 +1752,10 @@ nsDocument::~nsDocument()
|
|||
|
||||
delete mHeaderData;
|
||||
|
||||
MaybeClearBoxObjectTable();
|
||||
if (mBoxObjectTable) {
|
||||
mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nullptr);
|
||||
delete mBoxObjectTable;
|
||||
}
|
||||
|
||||
mPendingTitleChangeEvent.Revoke();
|
||||
|
||||
|
@ -1784,6 +1866,18 @@ RadioGroupsTraverser(const nsAString& aKey, nsRadioGroupStruct* aData,
|
|||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
BoxObjectTraverser(nsIContent* key, nsPIBoxObject* boxObject, void* userArg)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback *cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(userArg);
|
||||
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mBoxObjectTable entry");
|
||||
cb->NoteXPCOMChild(boxObject);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static const char* kNSURIs[] = {
|
||||
"([none])",
|
||||
"(xmlns)",
|
||||
|
@ -1865,11 +1959,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
|
|||
// The boxobject for an element will only exist as long as it's in the
|
||||
// document, so we'll traverse the table here instead of from the element.
|
||||
if (tmp->mBoxObjectTable) {
|
||||
for (auto iter = tmp->mBoxObjectTable->ConstIter(); !iter.Done();
|
||||
iter.Next()) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mBoxObjectTable entry");
|
||||
cb.NoteXPCOMChild(iter.UserData());
|
||||
}
|
||||
tmp->mBoxObjectTable->EnumerateRead(BoxObjectTraverser, &cb);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
|
||||
|
@ -1988,7 +2078,12 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
|||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages)
|
||||
|
||||
tmp->MaybeClearBoxObjectTable();
|
||||
|
||||
if (tmp->mBoxObjectTable) {
|
||||
tmp->mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nullptr);
|
||||
delete tmp->mBoxObjectTable;
|
||||
tmp->mBoxObjectTable = nullptr;
|
||||
}
|
||||
|
||||
if (tmp->mListenerManager) {
|
||||
tmp->mListenerManager->Disconnect();
|
||||
|
@ -3756,23 +3851,6 @@ nsDocument::MaybeRescheduleAnimationFrameNotifications()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::MaybeClearBoxObjectTable()
|
||||
{
|
||||
if (!mBoxObjectTable) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto iter = mBoxObjectTable->ConstIter(); !iter.Done(); iter.Next()) {
|
||||
if (auto boxObject = iter.UserData()) {
|
||||
boxObject->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
delete mBoxObjectTable;
|
||||
mBoxObjectTable = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks)
|
||||
{
|
||||
|
@ -3821,6 +3899,14 @@ nsIDocument::ShouldThrottleFrameRequests()
|
|||
return false;
|
||||
}
|
||||
|
||||
PLDHashOperator RequestDiscardEnumerator(imgIRequest* aKey,
|
||||
uint32_t aData,
|
||||
void* userArg)
|
||||
{
|
||||
aKey->RequestDiscard();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::DeleteShell()
|
||||
{
|
||||
|
@ -3835,9 +3921,7 @@ nsDocument::DeleteShell()
|
|||
// When our shell goes away, request that all our images be immediately
|
||||
// discarded, so we don't carry around decoded image data for a document we
|
||||
// no longer intend to paint.
|
||||
for (auto iter = mImageTracker.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
iter.Key()->RequestDiscard();
|
||||
}
|
||||
mImageTracker.EnumerateRead(RequestDiscardEnumerator, nullptr);
|
||||
|
||||
// Now that we no longer have a shell, we need to forget about any FontFace
|
||||
// objects for @font-face rules that came from the style set.
|
||||
|
@ -10545,6 +10629,24 @@ nsDocument::NotifyMediaFeatureValuesChanged()
|
|||
}
|
||||
}
|
||||
|
||||
PLDHashOperator LockEnumerator(imgIRequest* aKey,
|
||||
uint32_t aData,
|
||||
void* userArg)
|
||||
{
|
||||
aKey->LockImage();
|
||||
aKey->RequestDecode();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator UnlockEnumerator(imgIRequest* aKey,
|
||||
uint32_t aData,
|
||||
void* userArg)
|
||||
{
|
||||
aKey->UnlockImage();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsDocument::SetImageLockingState(bool aLocked)
|
||||
{
|
||||
|
@ -10558,15 +10660,9 @@ nsDocument::SetImageLockingState(bool aLocked)
|
|||
return NS_OK;
|
||||
|
||||
// Otherwise, iterate over our images and perform the appropriate action.
|
||||
for (auto iter = mImageTracker.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
imgIRequest* image = iter.Key();
|
||||
if (aLocked) {
|
||||
image->LockImage();
|
||||
image->RequestDecode();
|
||||
} else {
|
||||
image->UnlockImage();
|
||||
}
|
||||
}
|
||||
mImageTracker.EnumerateRead(aLocked ? LockEnumerator
|
||||
: UnlockEnumerator,
|
||||
nullptr);
|
||||
|
||||
// Update state.
|
||||
mLockingImages = aLocked;
|
||||
|
@ -10574,6 +10670,22 @@ nsDocument::SetImageLockingState(bool aLocked)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
PLDHashOperator IncrementAnimationEnumerator(imgIRequest* aKey,
|
||||
uint32_t aData,
|
||||
void* userArg)
|
||||
{
|
||||
aKey->IncrementAnimationConsumers();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
PLDHashOperator DecrementAnimationEnumerator(imgIRequest* aKey,
|
||||
uint32_t aData,
|
||||
void* userArg)
|
||||
{
|
||||
aKey->DecrementAnimationConsumers();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::SetImagesNeedAnimating(bool aAnimating)
|
||||
{
|
||||
|
@ -10582,14 +10694,9 @@ nsDocument::SetImagesNeedAnimating(bool aAnimating)
|
|||
return;
|
||||
|
||||
// Otherwise, iterate over our images and perform the appropriate action.
|
||||
for (auto iter = mImageTracker.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
imgIRequest* image = iter.Key();
|
||||
if (aAnimating) {
|
||||
image->IncrementAnimationConsumers();
|
||||
} else {
|
||||
image->DecrementAnimationConsumers();
|
||||
}
|
||||
}
|
||||
mImageTracker.EnumerateRead(aAnimating ? IncrementAnimationEnumerator
|
||||
: DecrementAnimationEnumerator,
|
||||
nullptr);
|
||||
|
||||
// Update state.
|
||||
mAnimatingImages = aAnimating;
|
||||
|
|
|
@ -1737,8 +1737,6 @@ private:
|
|||
// requestAnimationFrame, if it's OK to do so.
|
||||
void MaybeRescheduleAnimationFrameNotifications();
|
||||
|
||||
void MaybeClearBoxObjectTable();
|
||||
|
||||
// These are not implemented and not supported.
|
||||
nsDocument(const nsDocument& aOther);
|
||||
nsDocument& operator=(const nsDocument& aOther);
|
||||
|
|
|
@ -120,18 +120,26 @@ nsFrameMessageManager::~nsFrameMessageManager()
|
|||
}
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
CycleCollectorTraverseListeners(const nsAString& aKey,
|
||||
nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
|
||||
void* aCb)
|
||||
{
|
||||
nsCycleCollectionTraversalCallback* cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*> (aCb);
|
||||
uint32_t count = aListeners->Length();
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "listeners[i] mStrongListener");
|
||||
cb->NoteXPCOMChild(aListeners->ElementAt(i).mStrongListener.get());
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager)
|
||||
for (auto iter = tmp->mListeners.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto listeners = iter.UserData();
|
||||
const uint32_t count = listeners->Length();
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "listeners[i] mStrongListener");
|
||||
cb.NoteXPCOMChild(listeners->ElementAt(i).mStrongListener.get());
|
||||
}
|
||||
}
|
||||
tmp->mListeners.EnumerateRead(CycleCollectorTraverseListeners,
|
||||
static_cast<void*>(&cb));
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildManagers)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
|
@ -407,6 +415,35 @@ nsFrameMessageManager::RemoveMessageListener(const nsAString& aMessage,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
typedef struct
|
||||
{
|
||||
nsCOMPtr<nsISupports> mCanonical;
|
||||
nsWeakPtr mWeak;
|
||||
} CanonicalCheckerParams;
|
||||
|
||||
static PLDHashOperator
|
||||
CanonicalChecker(const nsAString& aKey,
|
||||
nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
|
||||
void* aParams)
|
||||
{
|
||||
CanonicalCheckerParams* params =
|
||||
static_cast<CanonicalCheckerParams*> (aParams);
|
||||
|
||||
uint32_t count = aListeners->Length();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (!aListeners->ElementAt(i).mWeakListener) {
|
||||
continue;
|
||||
}
|
||||
nsCOMPtr<nsISupports> otherCanonical =
|
||||
do_QueryReferent(aListeners->ElementAt(i).mWeakListener);
|
||||
MOZ_ASSERT((params->mCanonical == otherCanonical) ==
|
||||
(params->mWeak == aListeners->ElementAt(i).mWeakListener));
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage,
|
||||
nsIMessageListener* aListener)
|
||||
|
@ -415,24 +452,15 @@ nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage,
|
|||
NS_ENSURE_TRUE(weak, NS_ERROR_NO_INTERFACE);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// It's technically possible that one object X could give two different
|
||||
// nsIWeakReference*'s when you do_GetWeakReference(X). We really don't
|
||||
// want this to happen; it will break e.g. RemoveWeakMessageListener. So
|
||||
// let's check that we're not getting ourselves into that situation.
|
||||
nsCOMPtr<nsISupports> canonical = do_QueryInterface(aListener);
|
||||
|
||||
for (auto iter = mListeners.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto listeners = iter.UserData();
|
||||
const uint32_t count = listeners->Length();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (auto listener = listeners->ElementAt(i).mWeakListener) {
|
||||
nsCOMPtr<nsISupports> otherCanonical = do_QueryReferent(listener);
|
||||
MOZ_ASSERT((canonical == otherCanonical) == (weak == listener));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// It's technically possible that one object X could give two different
|
||||
// nsIWeakReference*'s when you do_GetWeakReference(X). We really don't want
|
||||
// this to happen; it will break e.g. RemoveWeakMessageListener. So let's
|
||||
// check that we're not getting ourselves into that situation.
|
||||
nsCOMPtr<nsISupports> canonical = do_QueryInterface(aListener);
|
||||
CanonicalCheckerParams params;
|
||||
params.mCanonical = canonical;
|
||||
params.mWeak = weak;
|
||||
mListeners.EnumerateRead(CanonicalChecker, (void*)¶ms);
|
||||
#endif
|
||||
|
||||
nsAutoTObserverArray<nsMessageListenerInfo, 1>* listeners =
|
||||
|
@ -1444,45 +1472,55 @@ protected:
|
|||
|
||||
NS_IMPL_ISUPPORTS(MessageManagerReporter, nsIMemoryReporter)
|
||||
|
||||
static PLDHashOperator
|
||||
CollectMessageListenerData(const nsAString& aKey,
|
||||
nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
|
||||
void* aData)
|
||||
{
|
||||
MessageManagerReferentCount* referentCount =
|
||||
static_cast<MessageManagerReferentCount*>(aData);
|
||||
|
||||
uint32_t listenerCount = aListeners->Length();
|
||||
if (!listenerCount) {
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
nsString key(aKey);
|
||||
uint32_t oldCount = 0;
|
||||
referentCount->mMessageCounter.Get(key, &oldCount);
|
||||
uint32_t currentCount = oldCount + listenerCount;
|
||||
referentCount->mMessageCounter.Put(key, currentCount);
|
||||
|
||||
// Keep track of messages that have a suspiciously large
|
||||
// number of referents (symptom of leak).
|
||||
if (currentCount == MessageManagerReporter::kSuspectReferentCount) {
|
||||
referentCount->mSuspectMessages.AppendElement(key);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < listenerCount; ++i) {
|
||||
const nsMessageListenerInfo& listenerInfo =
|
||||
aListeners->ElementAt(i);
|
||||
if (listenerInfo.mWeakListener) {
|
||||
nsCOMPtr<nsISupports> referent =
|
||||
do_QueryReferent(listenerInfo.mWeakListener);
|
||||
if (referent) {
|
||||
referentCount->mWeakAlive++;
|
||||
} else {
|
||||
referentCount->mWeakDead++;
|
||||
}
|
||||
} else {
|
||||
referentCount->mStrong++;
|
||||
}
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager,
|
||||
MessageManagerReferentCount* aReferentCount)
|
||||
{
|
||||
for (auto iter = aMessageManager->mListeners.ConstIter();
|
||||
!iter.Done(); iter.Next()) {
|
||||
auto listeners = iter.UserData();
|
||||
const uint32_t listenerCount = listeners->Length();
|
||||
if (!listenerCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsString key(iter.Key());
|
||||
uint32_t oldCount = 0;
|
||||
aReferentCount->mMessageCounter.Get(key, &oldCount);
|
||||
uint32_t currentCount = oldCount + listenerCount;
|
||||
aReferentCount->mMessageCounter.Put(key, currentCount);
|
||||
|
||||
// Keep track of messages that have a suspiciously large
|
||||
// number of referents (symptom of leak).
|
||||
if (currentCount == MessageManagerReporter::kSuspectReferentCount) {
|
||||
aReferentCount->mSuspectMessages.AppendElement(key);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < listenerCount; ++i) {
|
||||
const nsMessageListenerInfo& listenerInfo = listeners->ElementAt(i);
|
||||
if (listenerInfo.mWeakListener) {
|
||||
nsCOMPtr<nsISupports> referent =
|
||||
do_QueryReferent(listenerInfo.mWeakListener);
|
||||
if (referent) {
|
||||
aReferentCount->mWeakAlive++;
|
||||
} else {
|
||||
aReferentCount->mWeakDead++;
|
||||
}
|
||||
} else {
|
||||
aReferentCount->mStrong++;
|
||||
}
|
||||
}
|
||||
}
|
||||
aMessageManager->mListeners.EnumerateRead(CollectMessageListenerData,
|
||||
aReferentCount);
|
||||
|
||||
// Add referent count in child managers because the listeners
|
||||
// participate in messages dispatched from parent message manager.
|
||||
|
@ -2129,19 +2167,24 @@ NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
|
|||
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
CycleCollectorMarkListeners(const nsAString& aKey,
|
||||
nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
|
||||
void* aData)
|
||||
{
|
||||
uint32_t count = aListeners->Length();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (aListeners->ElementAt(i).mStrongListener) {
|
||||
xpc_TryUnmarkWrappedGrayObject(aListeners->ElementAt(i).mStrongListener);
|
||||
}
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
bool
|
||||
nsFrameMessageManager::MarkForCC()
|
||||
{
|
||||
for (auto iter = mListeners.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto listeners = iter.UserData();
|
||||
const uint32_t count = listeners->Length();
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (auto listener = listeners->ElementAt(i).mStrongListener) {
|
||||
xpc_TryUnmarkWrappedGrayObject(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
mListeners.EnumerateRead(CycleCollectorMarkListeners, nullptr);
|
||||
|
||||
if (mRefCnt.IsPurple()) {
|
||||
mRefCnt.RemovePurple();
|
||||
|
|
|
@ -316,13 +316,18 @@ nsXBLDocumentInfo::SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding)
|
|||
mFirstBinding = aBinding;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
FlushScopedSkinSheets(const nsACString &aKey, nsXBLPrototypeBinding *aProto, void* aClosure)
|
||||
{
|
||||
aProto->FlushSkinSheets();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
nsXBLDocumentInfo::FlushSkinStylesheets()
|
||||
{
|
||||
if (mBindingTable) {
|
||||
for (auto iter = mBindingTable->ConstIter(); !iter.Done(); iter.Next()) {
|
||||
iter.UserData()->FlushSkinSheets();
|
||||
}
|
||||
mBindingTable->EnumerateRead(FlushScopedSkinSheets, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче