1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/xbl/nsBindingManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1184 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=79: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsBindingManager.h" 1.11 + 1.12 +#include "nsCOMPtr.h" 1.13 +#include "nsXBLService.h" 1.14 +#include "nsIInputStream.h" 1.15 +#include "nsIURI.h" 1.16 +#include "nsIURL.h" 1.17 +#include "nsIChannel.h" 1.18 +#include "nsXPIDLString.h" 1.19 +#include "nsNetUtil.h" 1.20 +#include "plstr.h" 1.21 +#include "nsIContent.h" 1.22 +#include "nsIDOMElement.h" 1.23 +#include "nsIDocument.h" 1.24 +#include "nsContentUtils.h" 1.25 +#include "nsIPresShell.h" 1.26 +#include "nsIXMLContentSink.h" 1.27 +#include "nsContentCID.h" 1.28 +#include "mozilla/dom/XMLDocument.h" 1.29 +#include "nsIStreamListener.h" 1.30 +#include "ChildIterator.h" 1.31 + 1.32 +#include "nsXBLBinding.h" 1.33 +#include "nsXBLPrototypeBinding.h" 1.34 +#include "nsXBLDocumentInfo.h" 1.35 +#include "mozilla/dom/XBLChildrenElement.h" 1.36 + 1.37 +#include "nsIStyleRuleProcessor.h" 1.38 +#include "nsRuleProcessorData.h" 1.39 +#include "nsIWeakReference.h" 1.40 + 1.41 +#include "nsWrapperCacheInlines.h" 1.42 +#include "nsIXPConnect.h" 1.43 +#include "nsDOMCID.h" 1.44 +#include "nsIDOMScriptObjectFactory.h" 1.45 +#include "nsIScriptGlobalObject.h" 1.46 +#include "nsTHashtable.h" 1.47 + 1.48 +#include "nsIScriptContext.h" 1.49 +#include "xpcpublic.h" 1.50 +#include "jswrapper.h" 1.51 +#include "nsCxPusher.h" 1.52 + 1.53 +#include "nsThreadUtils.h" 1.54 +#include "mozilla/dom/NodeListBinding.h" 1.55 + 1.56 +using namespace mozilla; 1.57 +using namespace mozilla::dom; 1.58 + 1.59 +// Implement our nsISupports methods 1.60 + 1.61 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsBindingManager) 1.62 + 1.63 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBindingManager) 1.64 + tmp->mDestroyed = true; 1.65 + 1.66 + if (tmp->mBoundContentSet) 1.67 + tmp->mBoundContentSet->Clear(); 1.68 + 1.69 + if (tmp->mDocumentTable) 1.70 + tmp->mDocumentTable->Clear(); 1.71 + 1.72 + if (tmp->mLoadingDocTable) 1.73 + tmp->mLoadingDocTable->Clear(); 1.74 + 1.75 + if (tmp->mWrapperTable) { 1.76 + tmp->mWrapperTable->Clear(); 1.77 + tmp->mWrapperTable = nullptr; 1.78 + } 1.79 + 1.80 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mAttachedStack) 1.81 + 1.82 + if (tmp->mProcessAttachedQueueEvent) { 1.83 + tmp->mProcessAttachedQueueEvent->Revoke(); 1.84 + } 1.85 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.86 + 1.87 + 1.88 +static PLDHashOperator 1.89 +DocumentInfoHashtableTraverser(nsIURI* key, 1.90 + nsXBLDocumentInfo* di, 1.91 + void* userArg) 1.92 +{ 1.93 + nsCycleCollectionTraversalCallback *cb = 1.94 + static_cast<nsCycleCollectionTraversalCallback*>(userArg); 1.95 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mDocumentTable value"); 1.96 + cb->NoteXPCOMChild(di); 1.97 + return PL_DHASH_NEXT; 1.98 +} 1.99 + 1.100 +static PLDHashOperator 1.101 +LoadingDocHashtableTraverser(nsIURI* key, 1.102 + nsIStreamListener* sl, 1.103 + void* userArg) 1.104 +{ 1.105 + nsCycleCollectionTraversalCallback *cb = 1.106 + static_cast<nsCycleCollectionTraversalCallback*>(userArg); 1.107 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mLoadingDocTable value"); 1.108 + cb->NoteXPCOMChild(sl); 1.109 + return PL_DHASH_NEXT; 1.110 +} 1.111 + 1.112 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBindingManager) 1.113 + // The hashes keyed on nsIContent are traversed from the nsIContent itself. 1.114 + if (tmp->mDocumentTable) 1.115 + tmp->mDocumentTable->EnumerateRead(&DocumentInfoHashtableTraverser, &cb); 1.116 + if (tmp->mLoadingDocTable) 1.117 + tmp->mLoadingDocTable->EnumerateRead(&LoadingDocHashtableTraverser, &cb); 1.118 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttachedStack) 1.119 + // No need to traverse mProcessAttachedQueueEvent, since it'll just 1.120 + // fire at some point or become revoke and drop its ref to us. 1.121 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.122 + 1.123 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsBindingManager) 1.124 + NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) 1.125 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.126 +NS_INTERFACE_MAP_END 1.127 + 1.128 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBindingManager) 1.129 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBindingManager) 1.130 + 1.131 +// Constructors/Destructors 1.132 +nsBindingManager::nsBindingManager(nsIDocument* aDocument) 1.133 + : mProcessingAttachedStack(false), 1.134 + mDestroyed(false), 1.135 + mAttachedStackSizeOnOutermost(0), 1.136 + mDocument(aDocument) 1.137 +{ 1.138 +} 1.139 + 1.140 +nsBindingManager::~nsBindingManager(void) 1.141 +{ 1.142 + mDestroyed = true; 1.143 +} 1.144 + 1.145 +nsXBLBinding* 1.146 +nsBindingManager::GetBindingWithContent(nsIContent* aContent) 1.147 +{ 1.148 + nsXBLBinding* binding = aContent ? aContent->GetXBLBinding() : nullptr; 1.149 + return binding ? binding->GetBindingWithContent() : nullptr; 1.150 +} 1.151 + 1.152 +void 1.153 +nsBindingManager::AddBoundContent(nsIContent* aContent) 1.154 +{ 1.155 + if (!mBoundContentSet) { 1.156 + mBoundContentSet = new nsTHashtable<nsRefPtrHashKey<nsIContent> >; 1.157 + } 1.158 + mBoundContentSet->PutEntry(aContent); 1.159 +} 1.160 + 1.161 +void 1.162 +nsBindingManager::RemoveBoundContent(nsIContent* aContent) 1.163 +{ 1.164 + if (mBoundContentSet) { 1.165 + mBoundContentSet->RemoveEntry(aContent); 1.166 + } 1.167 + 1.168 + // The death of the bindings means the death of the JS wrapper. 1.169 + SetWrappedJS(aContent, nullptr); 1.170 +} 1.171 + 1.172 +nsIXPConnectWrappedJS* 1.173 +nsBindingManager::GetWrappedJS(nsIContent* aContent) 1.174 +{ 1.175 + if (!mWrapperTable) { 1.176 + return nullptr; 1.177 + } 1.178 + 1.179 + if (!aContent || !aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { 1.180 + return nullptr; 1.181 + } 1.182 + 1.183 + return mWrapperTable->GetWeak(aContent); 1.184 +} 1.185 + 1.186 +nsresult 1.187 +nsBindingManager::SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aWrappedJS) 1.188 +{ 1.189 + if (mDestroyed) { 1.190 + return NS_OK; 1.191 + } 1.192 + 1.193 + if (aWrappedJS) { 1.194 + // lazily create the table, but only when adding elements 1.195 + if (!mWrapperTable) { 1.196 + mWrapperTable = new WrapperHashtable(); 1.197 + } 1.198 + aContent->SetFlags(NODE_MAY_BE_IN_BINDING_MNGR); 1.199 + 1.200 + NS_ASSERTION(aContent, "key must be non-null"); 1.201 + if (!aContent) return NS_ERROR_INVALID_ARG; 1.202 + 1.203 + mWrapperTable->Put(aContent, aWrappedJS); 1.204 + 1.205 + return NS_OK; 1.206 + } 1.207 + 1.208 + // no value, so remove the key from the table 1.209 + if (mWrapperTable) { 1.210 + mWrapperTable->Remove(aContent); 1.211 + } 1.212 + 1.213 + return NS_OK; 1.214 +} 1.215 + 1.216 +void 1.217 +nsBindingManager::RemovedFromDocumentInternal(nsIContent* aContent, 1.218 + nsIDocument* aOldDocument) 1.219 +{ 1.220 + NS_PRECONDITION(aOldDocument != nullptr, "no old document"); 1.221 + 1.222 + if (mDestroyed) 1.223 + return; 1.224 + 1.225 + nsRefPtr<nsXBLBinding> binding = aContent->GetXBLBinding(); 1.226 + if (binding) { 1.227 + binding->PrototypeBinding()->BindingDetached(binding->GetBoundElement()); 1.228 + binding->ChangeDocument(aOldDocument, nullptr); 1.229 + aContent->SetXBLBinding(nullptr, this); 1.230 + } 1.231 + 1.232 + // Clear out insertion parents and content lists. 1.233 + aContent->SetXBLInsertionParent(nullptr); 1.234 +} 1.235 + 1.236 +nsIAtom* 1.237 +nsBindingManager::ResolveTag(nsIContent* aContent, int32_t* aNameSpaceID) 1.238 +{ 1.239 + nsXBLBinding *binding = aContent->GetXBLBinding(); 1.240 + 1.241 + if (binding) { 1.242 + nsIAtom* base = binding->GetBaseTag(aNameSpaceID); 1.243 + 1.244 + if (base) { 1.245 + return base; 1.246 + } 1.247 + } 1.248 + 1.249 + *aNameSpaceID = aContent->GetNameSpaceID(); 1.250 + return aContent->Tag(); 1.251 +} 1.252 + 1.253 +nsresult 1.254 +nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent, 1.255 + nsIDOMNodeList** aResult) 1.256 +{ 1.257 + NS_IF_ADDREF(*aResult = GetAnonymousNodesFor(aContent)); 1.258 + return NS_OK; 1.259 +} 1.260 + 1.261 +nsINodeList* 1.262 +nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent) 1.263 +{ 1.264 + nsXBLBinding* binding = GetBindingWithContent(aContent); 1.265 + return binding ? binding->GetAnonymousNodeList() : nullptr; 1.266 +} 1.267 + 1.268 +nsresult 1.269 +nsBindingManager::ClearBinding(nsIContent* aContent) 1.270 +{ 1.271 + // Hold a ref to the binding so it won't die when we remove it from our table 1.272 + nsRefPtr<nsXBLBinding> binding = 1.273 + aContent ? aContent->GetXBLBinding() : nullptr; 1.274 + 1.275 + if (!binding) { 1.276 + return NS_OK; 1.277 + } 1.278 + 1.279 + // For now we can only handle removing a binding if it's the only one 1.280 + NS_ENSURE_FALSE(binding->GetBaseBinding(), NS_ERROR_FAILURE); 1.281 + 1.282 + // Hold strong ref in case removing the binding tries to close the 1.283 + // window or something. 1.284 + // XXXbz should that be ownerdoc? Wouldn't we need a ref to the 1.285 + // currentdoc too? What's the one that should be passed to 1.286 + // ChangeDocument? 1.287 + nsCOMPtr<nsIDocument> doc = aContent->OwnerDoc(); 1.288 + 1.289 + // Finally remove the binding... 1.290 + // XXXbz this doesn't remove the implementation! Should fix! Until 1.291 + // then we need the explicit UnhookEventHandlers here. 1.292 + binding->UnhookEventHandlers(); 1.293 + binding->ChangeDocument(doc, nullptr); 1.294 + aContent->SetXBLBinding(nullptr, this); 1.295 + binding->MarkForDeath(); 1.296 + 1.297 + // ...and recreate its frames. We need to do this since the frames may have 1.298 + // been removed and style may have changed due to the removal of the 1.299 + // anonymous children. 1.300 + // XXXbz this should be using the current doc (if any), not the owner doc. 1.301 + nsIPresShell *presShell = doc->GetShell(); 1.302 + NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); 1.303 + 1.304 + return presShell->RecreateFramesFor(aContent);; 1.305 +} 1.306 + 1.307 +nsresult 1.308 +nsBindingManager::LoadBindingDocument(nsIDocument* aBoundDoc, 1.309 + nsIURI* aURL, 1.310 + nsIPrincipal* aOriginPrincipal) 1.311 +{ 1.312 + NS_PRECONDITION(aURL, "Must have a URI to load!"); 1.313 + 1.314 + // First we need to load our binding. 1.315 + nsXBLService* xblService = nsXBLService::GetInstance(); 1.316 + if (!xblService) 1.317 + return NS_ERROR_FAILURE; 1.318 + 1.319 + // Load the binding doc. 1.320 + nsRefPtr<nsXBLDocumentInfo> info; 1.321 + xblService->LoadBindingDocumentInfo(nullptr, aBoundDoc, aURL, 1.322 + aOriginPrincipal, true, 1.323 + getter_AddRefs(info)); 1.324 + if (!info) 1.325 + return NS_ERROR_FAILURE; 1.326 + 1.327 + return NS_OK; 1.328 +} 1.329 + 1.330 +void 1.331 +nsBindingManager::RemoveFromAttachedQueue(nsXBLBinding* aBinding) 1.332 +{ 1.333 + // Don't remove items here as that could mess up an executing 1.334 + // ProcessAttachedQueue. Instead, null the entry in the queue. 1.335 + uint32_t index = mAttachedStack.IndexOf(aBinding); 1.336 + if (index != mAttachedStack.NoIndex) { 1.337 + mAttachedStack[index] = nullptr; 1.338 + } 1.339 +} 1.340 + 1.341 +nsresult 1.342 +nsBindingManager::AddToAttachedQueue(nsXBLBinding* aBinding) 1.343 +{ 1.344 + if (!mAttachedStack.AppendElement(aBinding)) 1.345 + return NS_ERROR_OUT_OF_MEMORY; 1.346 + 1.347 + // If we're in the middle of processing our queue already, don't 1.348 + // bother posting the event. 1.349 + if (!mProcessingAttachedStack && !mProcessAttachedQueueEvent) { 1.350 + PostProcessAttachedQueueEvent(); 1.351 + } 1.352 + 1.353 + // Make sure that flushes will flush out the new items as needed. 1.354 + mDocument->SetNeedStyleFlush(); 1.355 + 1.356 + return NS_OK; 1.357 + 1.358 +} 1.359 + 1.360 +void 1.361 +nsBindingManager::PostProcessAttachedQueueEvent() 1.362 +{ 1.363 + mProcessAttachedQueueEvent = 1.364 + NS_NewRunnableMethod(this, &nsBindingManager::DoProcessAttachedQueue); 1.365 + nsresult rv = NS_DispatchToCurrentThread(mProcessAttachedQueueEvent); 1.366 + if (NS_SUCCEEDED(rv) && mDocument) { 1.367 + mDocument->BlockOnload(); 1.368 + } 1.369 +} 1.370 + 1.371 +void 1.372 +nsBindingManager::DoProcessAttachedQueue() 1.373 +{ 1.374 + if (!mProcessingAttachedStack) { 1.375 + ProcessAttachedQueue(); 1.376 + 1.377 + NS_ASSERTION(mAttachedStack.Length() == 0, 1.378 + "Shouldn't have pending bindings!"); 1.379 + 1.380 + mProcessAttachedQueueEvent = nullptr; 1.381 + } else { 1.382 + // Someone's doing event processing from inside a constructor. 1.383 + // They're evil, but we'll fight back! Just poll on them being 1.384 + // done and repost the attached queue event. 1.385 + PostProcessAttachedQueueEvent(); 1.386 + } 1.387 + 1.388 + // No matter what, unblock onload for the event that's fired. 1.389 + if (mDocument) { 1.390 + // Hold a strong reference while calling UnblockOnload since that might 1.391 + // run script. 1.392 + nsCOMPtr<nsIDocument> doc = mDocument; 1.393 + doc->UnblockOnload(true); 1.394 + } 1.395 +} 1.396 + 1.397 +void 1.398 +nsBindingManager::ProcessAttachedQueue(uint32_t aSkipSize) 1.399 +{ 1.400 + if (mProcessingAttachedStack || mAttachedStack.Length() <= aSkipSize) 1.401 + return; 1.402 + 1.403 + mProcessingAttachedStack = true; 1.404 + 1.405 + // Excute constructors. Do this from high index to low 1.406 + while (mAttachedStack.Length() > aSkipSize) { 1.407 + uint32_t lastItem = mAttachedStack.Length() - 1; 1.408 + nsRefPtr<nsXBLBinding> binding = mAttachedStack.ElementAt(lastItem); 1.409 + mAttachedStack.RemoveElementAt(lastItem); 1.410 + if (binding) { 1.411 + binding->ExecuteAttachedHandler(); 1.412 + } 1.413 + } 1.414 + 1.415 + // If NodeWillBeDestroyed has run we don't want to clobber 1.416 + // mProcessingAttachedStack set there. 1.417 + if (mDocument) { 1.418 + mProcessingAttachedStack = false; 1.419 + } 1.420 + 1.421 + NS_ASSERTION(mAttachedStack.Length() == aSkipSize, "How did we get here?"); 1.422 + 1.423 + mAttachedStack.Compact(); 1.424 +} 1.425 + 1.426 +// Keep bindings and bound elements alive while executing detached handlers. 1.427 +struct BindingTableReadClosure 1.428 +{ 1.429 + nsCOMArray<nsIContent> mBoundElements; 1.430 + nsBindingList mBindings; 1.431 +}; 1.432 + 1.433 +static PLDHashOperator 1.434 +AccumulateBindingsToDetach(nsRefPtrHashKey<nsIContent> *aKey, 1.435 + void* aClosure) 1.436 +{ 1.437 + nsXBLBinding *binding = aKey->GetKey()->GetXBLBinding(); 1.438 + BindingTableReadClosure* closure = 1.439 + static_cast<BindingTableReadClosure*>(aClosure); 1.440 + if (binding && closure->mBindings.AppendElement(binding)) { 1.441 + if (!closure->mBoundElements.AppendObject(binding->GetBoundElement())) { 1.442 + closure->mBindings.RemoveElementAt(closure->mBindings.Length() - 1); 1.443 + } 1.444 + } 1.445 + return PL_DHASH_NEXT; 1.446 +} 1.447 + 1.448 +void 1.449 +nsBindingManager::ExecuteDetachedHandlers() 1.450 +{ 1.451 + // Walk our hashtable of bindings. 1.452 + if (mBoundContentSet) { 1.453 + BindingTableReadClosure closure; 1.454 + mBoundContentSet->EnumerateEntries(AccumulateBindingsToDetach, &closure); 1.455 + uint32_t i, count = closure.mBindings.Length(); 1.456 + for (i = 0; i < count; ++i) { 1.457 + closure.mBindings[i]->ExecuteDetachedHandler(); 1.458 + } 1.459 + } 1.460 +} 1.461 + 1.462 +nsresult 1.463 +nsBindingManager::PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo) 1.464 +{ 1.465 + NS_PRECONDITION(aDocumentInfo, "Must have a non-null documentinfo!"); 1.466 + 1.467 + if (!mDocumentTable) { 1.468 + mDocumentTable = new nsRefPtrHashtable<nsURIHashKey,nsXBLDocumentInfo>(16); 1.469 + } 1.470 + 1.471 + mDocumentTable->Put(aDocumentInfo->DocumentURI(), aDocumentInfo); 1.472 + 1.473 + return NS_OK; 1.474 +} 1.475 + 1.476 +void 1.477 +nsBindingManager::RemoveXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo) 1.478 +{ 1.479 + if (mDocumentTable) { 1.480 + mDocumentTable->Remove(aDocumentInfo->DocumentURI()); 1.481 + } 1.482 +} 1.483 + 1.484 +nsXBLDocumentInfo* 1.485 +nsBindingManager::GetXBLDocumentInfo(nsIURI* aURL) 1.486 +{ 1.487 + if (!mDocumentTable) 1.488 + return nullptr; 1.489 + 1.490 + return mDocumentTable->GetWeak(aURL); 1.491 +} 1.492 + 1.493 +nsresult 1.494 +nsBindingManager::PutLoadingDocListener(nsIURI* aURL, nsIStreamListener* aListener) 1.495 +{ 1.496 + NS_PRECONDITION(aListener, "Must have a non-null listener!"); 1.497 + 1.498 + if (!mLoadingDocTable) { 1.499 + mLoadingDocTable = new nsInterfaceHashtable<nsURIHashKey,nsIStreamListener>(16); 1.500 + } 1.501 + mLoadingDocTable->Put(aURL, aListener); 1.502 + 1.503 + return NS_OK; 1.504 +} 1.505 + 1.506 +nsIStreamListener* 1.507 +nsBindingManager::GetLoadingDocListener(nsIURI* aURL) 1.508 +{ 1.509 + if (!mLoadingDocTable) 1.510 + return nullptr; 1.511 + 1.512 + return mLoadingDocTable->GetWeak(aURL); 1.513 +} 1.514 + 1.515 +void 1.516 +nsBindingManager::RemoveLoadingDocListener(nsIURI* aURL) 1.517 +{ 1.518 + if (mLoadingDocTable) { 1.519 + mLoadingDocTable->Remove(aURL); 1.520 + } 1.521 +} 1.522 + 1.523 +static PLDHashOperator 1.524 +MarkForDeath(nsRefPtrHashKey<nsIContent> *aKey, void* aClosure) 1.525 +{ 1.526 + nsXBLBinding *binding = aKey->GetKey()->GetXBLBinding(); 1.527 + 1.528 + if (binding->MarkedForDeath()) 1.529 + return PL_DHASH_NEXT; // Already marked for death. 1.530 + 1.531 + nsAutoCString path; 1.532 + binding->PrototypeBinding()->DocURI()->GetPath(path); 1.533 + 1.534 + if (!strncmp(path.get(), "/skin", 5)) 1.535 + binding->MarkForDeath(); 1.536 + 1.537 + return PL_DHASH_NEXT; 1.538 +} 1.539 + 1.540 +void 1.541 +nsBindingManager::FlushSkinBindings() 1.542 +{ 1.543 + if (mBoundContentSet) { 1.544 + mBoundContentSet->EnumerateEntries(MarkForDeath, nullptr); 1.545 + } 1.546 +} 1.547 + 1.548 +// Used below to protect from recurring in QI calls through XPConnect. 1.549 +struct AntiRecursionData { 1.550 + nsIContent* element; 1.551 + REFNSIID iid; 1.552 + AntiRecursionData* next; 1.553 + 1.554 + AntiRecursionData(nsIContent* aElement, 1.555 + REFNSIID aIID, 1.556 + AntiRecursionData* aNext) 1.557 + : element(aElement), iid(aIID), next(aNext) {} 1.558 +}; 1.559 + 1.560 +nsresult 1.561 +nsBindingManager::GetBindingImplementation(nsIContent* aContent, REFNSIID aIID, 1.562 + void** aResult) 1.563 +{ 1.564 + *aResult = nullptr; 1.565 + nsXBLBinding *binding = aContent ? aContent->GetXBLBinding() : nullptr; 1.566 + if (binding) { 1.567 + // The binding should not be asked for nsISupports 1.568 + NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsISupports)), "Asking a binding for nsISupports"); 1.569 + if (binding->ImplementsInterface(aIID)) { 1.570 + nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = GetWrappedJS(aContent); 1.571 + 1.572 + if (wrappedJS) { 1.573 + // Protect from recurring in QI calls through XPConnect. 1.574 + // This can happen when a second binding is being resolved. 1.575 + // At that point a wrappedJS exists, but it doesn't yet know about 1.576 + // the iid we are asking for. So, without this protection, 1.577 + // AggregatedQueryInterface would end up recurring back into itself 1.578 + // through this code. 1.579 + // 1.580 + // With this protection, when we detect the recursion we return 1.581 + // NS_NOINTERFACE in the inner call. The outer call will then fall 1.582 + // through (see below) and build a new chained wrappedJS for the iid. 1.583 + // 1.584 + // We're careful to not assume that only one direct nesting can occur 1.585 + // because there is a call into JS in the middle and we can't assume 1.586 + // that this code won't be reached by some more complex nesting path. 1.587 + // 1.588 + // NOTE: We *assume* this is single threaded, so we can use a 1.589 + // static linked list to do the check. 1.590 + 1.591 + static AntiRecursionData* list = nullptr; 1.592 + 1.593 + for (AntiRecursionData* p = list; p; p = p->next) { 1.594 + if (p->element == aContent && p->iid.Equals(aIID)) { 1.595 + *aResult = nullptr; 1.596 + return NS_NOINTERFACE; 1.597 + } 1.598 + } 1.599 + 1.600 + AntiRecursionData item(aContent, aIID, list); 1.601 + list = &item; 1.602 + 1.603 + nsresult rv = wrappedJS->AggregatedQueryInterface(aIID, aResult); 1.604 + 1.605 + list = item.next; 1.606 + 1.607 + if (*aResult) 1.608 + return rv; 1.609 + 1.610 + // No result was found, so this must be another XBL interface. 1.611 + // Fall through to create a new wrapper. 1.612 + } 1.613 + 1.614 + // We have never made a wrapper for this implementation. 1.615 + // Create an XPC wrapper for the script object and hand it back. 1.616 + 1.617 + nsIDocument* doc = aContent->OwnerDoc(); 1.618 + 1.619 + nsCOMPtr<nsIScriptGlobalObject> global = 1.620 + do_QueryInterface(doc->GetWindow()); 1.621 + if (!global) 1.622 + return NS_NOINTERFACE; 1.623 + 1.624 + nsIScriptContext *context = global->GetContext(); 1.625 + if (!context) 1.626 + return NS_NOINTERFACE; 1.627 + 1.628 + AutoPushJSContext cx(context->GetNativeContext()); 1.629 + if (!cx) 1.630 + return NS_NOINTERFACE; 1.631 + 1.632 + nsIXPConnect *xpConnect = nsContentUtils::XPConnect(); 1.633 + 1.634 + JS::Rooted<JSObject*> jsobj(cx, aContent->GetWrapper()); 1.635 + NS_ENSURE_TRUE(jsobj, NS_NOINTERFACE); 1.636 + 1.637 + // If we're using an XBL scope, we need to use the Xray view to the bound 1.638 + // content in order to view the full array of methods defined in the 1.639 + // binding, some of which may not be exposed on the prototype of 1.640 + // untrusted content. 1.641 + // 1.642 + // If there's no separate XBL scope, or if the reflector itself lives in 1.643 + // the XBL scope, we'll end up with the global of the reflector, and this 1.644 + // will all be a no-op. 1.645 + JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScopeOrGlobal(cx, jsobj)); 1.646 + NS_ENSURE_TRUE(xblScope, NS_ERROR_UNEXPECTED); 1.647 + JSAutoCompartment ac(cx, xblScope); 1.648 + bool ok = JS_WrapObject(cx, &jsobj); 1.649 + NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY); 1.650 + MOZ_ASSERT_IF(js::IsWrapper(jsobj), xpc::IsXrayWrapper(jsobj)); 1.651 + 1.652 + nsresult rv = xpConnect->WrapJSAggregatedToNative(aContent, cx, 1.653 + jsobj, aIID, aResult); 1.654 + if (NS_FAILED(rv)) 1.655 + return rv; 1.656 + 1.657 + // We successfully created a wrapper. We will own this wrapper for as long as the binding remains 1.658 + // alive. At the time the binding is cleared out of the bindingManager, we will remove the wrapper 1.659 + // from the bindingManager as well. 1.660 + nsISupports* supp = static_cast<nsISupports*>(*aResult); 1.661 + wrappedJS = do_QueryInterface(supp); 1.662 + SetWrappedJS(aContent, wrappedJS); 1.663 + 1.664 + return rv; 1.665 + } 1.666 + } 1.667 + 1.668 + *aResult = nullptr; 1.669 + return NS_NOINTERFACE; 1.670 +} 1.671 + 1.672 +nsresult 1.673 +nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, 1.674 + ElementDependentRuleProcessorData* aData, 1.675 + bool* aCutOffInheritance) 1.676 +{ 1.677 + *aCutOffInheritance = false; 1.678 + 1.679 + NS_ASSERTION(aData->mElement, "How did that happen?"); 1.680 + 1.681 + // Walk the binding scope chain, starting with the binding attached to our 1.682 + // content, up till we run out of scopes or we get cut off. 1.683 + nsIContent *content = aData->mElement; 1.684 + 1.685 + do { 1.686 + nsXBLBinding *binding = content->GetXBLBinding(); 1.687 + if (binding) { 1.688 + aData->mTreeMatchContext.mScopedRoot = content; 1.689 + binding->WalkRules(aFunc, aData); 1.690 + // If we're not looking at our original content, allow the binding to cut 1.691 + // off style inheritance 1.692 + if (content != aData->mElement) { 1.693 + if (!binding->InheritsStyle()) { 1.694 + // Go no further; we're not inheriting style from anything above here 1.695 + break; 1.696 + } 1.697 + } 1.698 + } 1.699 + 1.700 + if (content->IsRootOfNativeAnonymousSubtree()) { 1.701 + break; // Deliberately cut off style inheritance here. 1.702 + } 1.703 + 1.704 + content = content->GetBindingParent(); 1.705 + } while (content); 1.706 + 1.707 + // If "content" is non-null that means we cut off inheritance at some point 1.708 + // in the loop. 1.709 + *aCutOffInheritance = (content != nullptr); 1.710 + 1.711 + // Null out the scoped root that we set repeatedly 1.712 + aData->mTreeMatchContext.mScopedRoot = nullptr; 1.713 + 1.714 + return NS_OK; 1.715 +} 1.716 + 1.717 +typedef nsTHashtable<nsPtrHashKey<nsIStyleRuleProcessor> > RuleProcessorSet; 1.718 + 1.719 +static PLDHashOperator 1.720 +EnumRuleProcessors(nsRefPtrHashKey<nsIContent> *aKey, void* aClosure) 1.721 +{ 1.722 + nsIContent *boundContent = aKey->GetKey(); 1.723 + nsAutoPtr<RuleProcessorSet> *set = static_cast<nsAutoPtr<RuleProcessorSet>*>(aClosure); 1.724 + for (nsXBLBinding *binding = boundContent->GetXBLBinding(); binding; 1.725 + binding = binding->GetBaseBinding()) { 1.726 + nsIStyleRuleProcessor *ruleProc = 1.727 + binding->PrototypeBinding()->GetRuleProcessor(); 1.728 + if (ruleProc) { 1.729 + if (!(*set)) { 1.730 + *set = new RuleProcessorSet; 1.731 + } 1.732 + (*set)->PutEntry(ruleProc); 1.733 + } 1.734 + } 1.735 + return PL_DHASH_NEXT; 1.736 +} 1.737 + 1.738 +struct WalkAllRulesData { 1.739 + nsIStyleRuleProcessor::EnumFunc mFunc; 1.740 + ElementDependentRuleProcessorData* mData; 1.741 +}; 1.742 + 1.743 +static PLDHashOperator 1.744 +EnumWalkAllRules(nsPtrHashKey<nsIStyleRuleProcessor> *aKey, void* aClosure) 1.745 +{ 1.746 + nsIStyleRuleProcessor *ruleProcessor = aKey->GetKey(); 1.747 + 1.748 + WalkAllRulesData *data = static_cast<WalkAllRulesData*>(aClosure); 1.749 + 1.750 + (*(data->mFunc))(ruleProcessor, data->mData); 1.751 + 1.752 + return PL_DHASH_NEXT; 1.753 +} 1.754 + 1.755 +void 1.756 +nsBindingManager::WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc, 1.757 + ElementDependentRuleProcessorData* aData) 1.758 +{ 1.759 + if (!mBoundContentSet) { 1.760 + return; 1.761 + } 1.762 + 1.763 + nsAutoPtr<RuleProcessorSet> set; 1.764 + mBoundContentSet->EnumerateEntries(EnumRuleProcessors, &set); 1.765 + if (!set) 1.766 + return; 1.767 + 1.768 + WalkAllRulesData data = { aFunc, aData }; 1.769 + set->EnumerateEntries(EnumWalkAllRules, &data); 1.770 +} 1.771 + 1.772 +struct MediumFeaturesChangedData { 1.773 + nsPresContext *mPresContext; 1.774 + bool *mRulesChanged; 1.775 +}; 1.776 + 1.777 +static PLDHashOperator 1.778 +EnumMediumFeaturesChanged(nsPtrHashKey<nsIStyleRuleProcessor> *aKey, void* aClosure) 1.779 +{ 1.780 + nsIStyleRuleProcessor *ruleProcessor = aKey->GetKey(); 1.781 + 1.782 + MediumFeaturesChangedData *data = 1.783 + static_cast<MediumFeaturesChangedData*>(aClosure); 1.784 + 1.785 + bool thisChanged = ruleProcessor->MediumFeaturesChanged(data->mPresContext); 1.786 + *data->mRulesChanged = *data->mRulesChanged || thisChanged; 1.787 + 1.788 + return PL_DHASH_NEXT; 1.789 +} 1.790 + 1.791 +nsresult 1.792 +nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext, 1.793 + bool* aRulesChanged) 1.794 +{ 1.795 + *aRulesChanged = false; 1.796 + if (!mBoundContentSet) { 1.797 + return NS_OK; 1.798 + } 1.799 + 1.800 + nsAutoPtr<RuleProcessorSet> set; 1.801 + mBoundContentSet->EnumerateEntries(EnumRuleProcessors, &set); 1.802 + if (!set) { 1.803 + return NS_OK; 1.804 + } 1.805 + 1.806 + MediumFeaturesChangedData data = { aPresContext, aRulesChanged }; 1.807 + set->EnumerateEntries(EnumMediumFeaturesChanged, &data); 1.808 + return NS_OK; 1.809 +} 1.810 + 1.811 +static PLDHashOperator 1.812 +EnumAppendAllSheets(nsRefPtrHashKey<nsIContent> *aKey, void* aClosure) 1.813 +{ 1.814 + nsIContent *boundContent = aKey->GetKey(); 1.815 + nsTArray<nsCSSStyleSheet*>* array = 1.816 + static_cast<nsTArray<nsCSSStyleSheet*>*>(aClosure); 1.817 + for (nsXBLBinding *binding = boundContent->GetXBLBinding(); binding; 1.818 + binding = binding->GetBaseBinding()) { 1.819 + nsXBLPrototypeResources::sheet_array_type* sheets = 1.820 + binding->PrototypeBinding()->GetStyleSheets(); 1.821 + if (sheets) { 1.822 + // Copy from nsTArray<nsRefPtr<nsCSSStyleSheet> > to 1.823 + // nsTArray<nsCSSStyleSheet*>. 1.824 + array->AppendElements(*sheets); 1.825 + } 1.826 + } 1.827 + return PL_DHASH_NEXT; 1.828 +} 1.829 + 1.830 +void 1.831 +nsBindingManager::AppendAllSheets(nsTArray<nsCSSStyleSheet*>& aArray) 1.832 +{ 1.833 + if (mBoundContentSet) { 1.834 + mBoundContentSet->EnumerateEntries(EnumAppendAllSheets, &aArray); 1.835 + } 1.836 +} 1.837 + 1.838 +static void 1.839 +InsertAppendedContent(XBLChildrenElement* aPoint, 1.840 + nsIContent* aFirstNewContent) 1.841 +{ 1.842 + uint32_t insertionIndex; 1.843 + if (nsIContent* prevSibling = aFirstNewContent->GetPreviousSibling()) { 1.844 + // If we have a previous sibling, then it must already be in aPoint. Find 1.845 + // it and insert after it. 1.846 + insertionIndex = aPoint->IndexOfInsertedChild(prevSibling); 1.847 + MOZ_ASSERT(insertionIndex != aPoint->NoIndex); 1.848 + 1.849 + // Our insertion index is one after our previous sibling's index. 1.850 + ++insertionIndex; 1.851 + } else { 1.852 + // Otherwise, we append. 1.853 + // TODO This is wrong for nested insertion points. In that case, we need to 1.854 + // keep track of the right index to insert into. 1.855 + insertionIndex = aPoint->mInsertedChildren.Length(); 1.856 + } 1.857 + 1.858 + // Do the inserting. 1.859 + for (nsIContent* currentChild = aFirstNewContent; 1.860 + currentChild; 1.861 + currentChild = currentChild->GetNextSibling()) { 1.862 + aPoint->InsertInsertedChildAt(currentChild, insertionIndex++); 1.863 + } 1.864 +} 1.865 + 1.866 +void 1.867 +nsBindingManager::ContentAppended(nsIDocument* aDocument, 1.868 + nsIContent* aContainer, 1.869 + nsIContent* aFirstNewContent, 1.870 + int32_t aNewIndexInContainer) 1.871 +{ 1.872 + if (aNewIndexInContainer == -1) { 1.873 + return; 1.874 + } 1.875 + 1.876 + // Try to find insertion points for all the new kids. 1.877 + XBLChildrenElement* point = nullptr; 1.878 + nsIContent* parent = aContainer; 1.879 + bool first = true; 1.880 + do { 1.881 + nsXBLBinding* binding = GetBindingWithContent(parent); 1.882 + if (!binding) { 1.883 + break; 1.884 + } 1.885 + 1.886 + if (binding->HasFilteredInsertionPoints()) { 1.887 + // There are filtered insertion points involved, handle each child 1.888 + // separately. 1.889 + // We could optimize this in the case when we've nested a few levels 1.890 + // deep already, without hitting bindings that have filtered insertion 1.891 + // points. 1.892 + int32_t currentIndex = aNewIndexInContainer; 1.893 + for (nsIContent* currentChild = aFirstNewContent; currentChild; 1.894 + currentChild = currentChild->GetNextSibling()) { 1.895 + HandleChildInsertion(aContainer, currentChild, 1.896 + currentIndex++, true); 1.897 + } 1.898 + 1.899 + return; 1.900 + } 1.901 + 1.902 + point = binding->GetDefaultInsertionPoint(); 1.903 + if (!point) { 1.904 + break; 1.905 + } 1.906 + 1.907 + // Even though we're in ContentAppended, nested insertion points force us 1.908 + // to deal with this append as an insertion except in the outermost 1.909 + // binding. 1.910 + if (first) { 1.911 + first = false; 1.912 + for (nsIContent* child = aFirstNewContent; child; 1.913 + child = child->GetNextSibling()) { 1.914 + point->AppendInsertedChild(child); 1.915 + } 1.916 + } else { 1.917 + InsertAppendedContent(point, aFirstNewContent); 1.918 + } 1.919 + 1.920 + nsIContent* newParent = point->GetParent(); 1.921 + if (newParent == parent) { 1.922 + break; 1.923 + } 1.924 + parent = newParent; 1.925 + } while (parent); 1.926 +} 1.927 + 1.928 +void 1.929 +nsBindingManager::ContentInserted(nsIDocument* aDocument, 1.930 + nsIContent* aContainer, 1.931 + nsIContent* aChild, 1.932 + int32_t aIndexInContainer) 1.933 +{ 1.934 + if (aIndexInContainer == -1) { 1.935 + return; 1.936 + } 1.937 + 1.938 + HandleChildInsertion(aContainer, aChild, aIndexInContainer, false); 1.939 +} 1.940 + 1.941 +void 1.942 +nsBindingManager::ContentRemoved(nsIDocument* aDocument, 1.943 + nsIContent* aContainer, 1.944 + nsIContent* aChild, 1.945 + int32_t aIndexInContainer, 1.946 + nsIContent* aPreviousSibling) 1.947 +{ 1.948 + aChild->SetXBLInsertionParent(nullptr); 1.949 + 1.950 + XBLChildrenElement* point = nullptr; 1.951 + nsIContent* parent = aContainer; 1.952 + do { 1.953 + nsXBLBinding* binding = GetBindingWithContent(parent); 1.954 + if (!binding) { 1.955 + // If aChild is XBL content, it might have <xbl:children> elements 1.956 + // somewhere under it. We need to inform those elements that they're no 1.957 + // longer in the tree so they can tell their distributed children that 1.958 + // they're no longer distributed under them. 1.959 + // XXX This is wrong. We need to do far more work to update the parent 1.960 + // binding's list of insertion points and to get the new insertion parent 1.961 + // for the newly-distributed children correct. 1.962 + if (aChild->GetBindingParent()) { 1.963 + ClearInsertionPointsRecursively(aChild); 1.964 + } 1.965 + return; 1.966 + } 1.967 + 1.968 + point = binding->FindInsertionPointFor(aChild); 1.969 + if (!point) { 1.970 + break; 1.971 + } 1.972 + 1.973 + point->RemoveInsertedChild(aChild); 1.974 + 1.975 + nsIContent* newParent = point->GetParent(); 1.976 + if (newParent == parent) { 1.977 + break; 1.978 + } 1.979 + parent = newParent; 1.980 + } while (parent); 1.981 +} 1.982 + 1.983 +void 1.984 +nsBindingManager::ClearInsertionPointsRecursively(nsIContent* aContent) 1.985 +{ 1.986 + if (aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) { 1.987 + static_cast<XBLChildrenElement*>(aContent)->ClearInsertedChildren(); 1.988 + } 1.989 + 1.990 + for (nsIContent* child = aContent->GetFirstChild(); child; 1.991 + child = child->GetNextSibling()) { 1.992 + ClearInsertionPointsRecursively(child); 1.993 + } 1.994 +} 1.995 + 1.996 +void 1.997 +nsBindingManager::DropDocumentReference() 1.998 +{ 1.999 + mDestroyed = true; 1.1000 + 1.1001 + // Make sure to not run any more XBL constructors 1.1002 + mProcessingAttachedStack = true; 1.1003 + if (mProcessAttachedQueueEvent) { 1.1004 + mProcessAttachedQueueEvent->Revoke(); 1.1005 + } 1.1006 + 1.1007 + if (mBoundContentSet) { 1.1008 + mBoundContentSet->Clear(); 1.1009 + } 1.1010 + 1.1011 + mDocument = nullptr; 1.1012 +} 1.1013 + 1.1014 +void 1.1015 +nsBindingManager::Traverse(nsIContent *aContent, 1.1016 + nsCycleCollectionTraversalCallback &cb) 1.1017 +{ 1.1018 + if (!aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) || 1.1019 + !aContent->IsElement()) { 1.1020 + // Don't traverse if content is not in this binding manager. 1.1021 + // We also don't traverse non-elements because there should not 1.1022 + // be bindings (checking the flag alone is not sufficient because 1.1023 + // the flag is also set on children of insertion points that may be 1.1024 + // non-elements). 1.1025 + return; 1.1026 + } 1.1027 + 1.1028 + if (mBoundContentSet && mBoundContentSet->Contains(aContent)) { 1.1029 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mBoundContentSet entry"); 1.1030 + cb.NoteXPCOMChild(aContent); 1.1031 + } 1.1032 + 1.1033 + nsIXPConnectWrappedJS *value = GetWrappedJS(aContent); 1.1034 + if (value) { 1.1035 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mWrapperTable key"); 1.1036 + cb.NoteXPCOMChild(aContent); 1.1037 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mWrapperTable value"); 1.1038 + cb.NoteXPCOMChild(value); 1.1039 + } 1.1040 +} 1.1041 + 1.1042 +void 1.1043 +nsBindingManager::BeginOutermostUpdate() 1.1044 +{ 1.1045 + mAttachedStackSizeOnOutermost = mAttachedStack.Length(); 1.1046 +} 1.1047 + 1.1048 +void 1.1049 +nsBindingManager::EndOutermostUpdate() 1.1050 +{ 1.1051 + if (!mProcessingAttachedStack) { 1.1052 + ProcessAttachedQueue(mAttachedStackSizeOnOutermost); 1.1053 + mAttachedStackSizeOnOutermost = 0; 1.1054 + } 1.1055 +} 1.1056 + 1.1057 +void 1.1058 +nsBindingManager::HandleChildInsertion(nsIContent* aContainer, 1.1059 + nsIContent* aChild, 1.1060 + uint32_t aIndexInContainer, 1.1061 + bool aAppend) 1.1062 +{ 1.1063 + NS_PRECONDITION(aChild, "Must have child"); 1.1064 + NS_PRECONDITION(!aContainer || 1.1065 + uint32_t(aContainer->IndexOf(aChild)) == aIndexInContainer, 1.1066 + "Child not at the right index?"); 1.1067 + 1.1068 + XBLChildrenElement* point = nullptr; 1.1069 + nsIContent* parent = aContainer; 1.1070 + while (parent) { 1.1071 + nsXBLBinding* binding = GetBindingWithContent(parent); 1.1072 + if (!binding) { 1.1073 + break; 1.1074 + } 1.1075 + 1.1076 + point = binding->FindInsertionPointFor(aChild); 1.1077 + if (!point) { 1.1078 + break; 1.1079 + } 1.1080 + 1.1081 + // Insert the child into the proper insertion point. 1.1082 + // TODO If there were multiple insertion points, this approximation can be 1.1083 + // wrong. We need to re-run the distribution algorithm. In the meantime, 1.1084 + // this should work well enough. 1.1085 + uint32_t index = aAppend ? point->mInsertedChildren.Length() : 0; 1.1086 + for (nsIContent* currentSibling = aChild->GetPreviousSibling(); 1.1087 + currentSibling; 1.1088 + currentSibling = currentSibling->GetPreviousSibling()) { 1.1089 + // If we find one of our previous siblings in the insertion point, the 1.1090 + // index following it is the correct insertion point. Otherwise, we guess 1.1091 + // based on whether we're appending or inserting. 1.1092 + uint32_t pointIndex = point->IndexOfInsertedChild(currentSibling); 1.1093 + if (pointIndex != point->NoIndex) { 1.1094 + index = pointIndex + 1; 1.1095 + break; 1.1096 + } 1.1097 + } 1.1098 + 1.1099 + point->InsertInsertedChildAt(aChild, index); 1.1100 + 1.1101 + nsIContent* newParent = point->GetParent(); 1.1102 + if (newParent == parent) { 1.1103 + break; 1.1104 + } 1.1105 + 1.1106 + parent = newParent; 1.1107 + } 1.1108 +} 1.1109 + 1.1110 + 1.1111 +nsIContent* 1.1112 +nsBindingManager::FindNestedInsertionPoint(nsIContent* aContainer, 1.1113 + nsIContent* aChild) 1.1114 +{ 1.1115 + NS_PRECONDITION(aChild->GetParent() == aContainer, 1.1116 + "Wrong container"); 1.1117 + 1.1118 + nsIContent* parent = aContainer; 1.1119 + if (aContainer->IsActiveChildrenElement()) { 1.1120 + if (static_cast<XBLChildrenElement*>(aContainer)-> 1.1121 + HasInsertedChildren()) { 1.1122 + return nullptr; 1.1123 + } 1.1124 + parent = aContainer->GetParent(); 1.1125 + } 1.1126 + 1.1127 + while (parent) { 1.1128 + nsXBLBinding* binding = GetBindingWithContent(parent); 1.1129 + if (!binding) { 1.1130 + break; 1.1131 + } 1.1132 + 1.1133 + XBLChildrenElement* point = binding->FindInsertionPointFor(aChild); 1.1134 + if (!point) { 1.1135 + return nullptr; 1.1136 + } 1.1137 + 1.1138 + nsIContent* newParent = point->GetParent(); 1.1139 + if (newParent == parent) { 1.1140 + break; 1.1141 + } 1.1142 + parent = newParent; 1.1143 + } 1.1144 + 1.1145 + return parent; 1.1146 +} 1.1147 + 1.1148 +nsIContent* 1.1149 +nsBindingManager::FindNestedSingleInsertionPoint(nsIContent* aContainer, 1.1150 + bool* aMulti) 1.1151 +{ 1.1152 + *aMulti = false; 1.1153 + 1.1154 + nsIContent* parent = aContainer; 1.1155 + if (aContainer->IsActiveChildrenElement()) { 1.1156 + if (static_cast<XBLChildrenElement*>(aContainer)-> 1.1157 + HasInsertedChildren()) { 1.1158 + return nullptr; 1.1159 + } 1.1160 + parent = aContainer->GetParent(); 1.1161 + } 1.1162 + 1.1163 + while(parent) { 1.1164 + nsXBLBinding* binding = GetBindingWithContent(parent); 1.1165 + if (!binding) { 1.1166 + break; 1.1167 + } 1.1168 + 1.1169 + if (binding->HasFilteredInsertionPoints()) { 1.1170 + *aMulti = true; 1.1171 + return nullptr; 1.1172 + } 1.1173 + 1.1174 + XBLChildrenElement* point = binding->GetDefaultInsertionPoint(); 1.1175 + if (!point) { 1.1176 + return nullptr; 1.1177 + } 1.1178 + 1.1179 + nsIContent* newParent = point->GetParent(); 1.1180 + if (newParent == parent) { 1.1181 + break; 1.1182 + } 1.1183 + parent = newParent; 1.1184 + } 1.1185 + 1.1186 + return parent; 1.1187 +}