LCOV - code coverage report
Current view: top level - dom/xbl - nsBindingManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 328 505 65.0 %
Date: 2017-07-14 16:53:18 Functions: 36 50 72.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsBindingManager.h"
       8             : 
       9             : #include "nsAutoPtr.h"
      10             : #include "nsCOMPtr.h"
      11             : #include "nsXBLService.h"
      12             : #include "nsIInputStream.h"
      13             : #include "nsIURI.h"
      14             : #include "nsIURL.h"
      15             : #include "nsIChannel.h"
      16             : #include "nsXPIDLString.h"
      17             : #include "plstr.h"
      18             : #include "nsIContent.h"
      19             : #include "nsIDOMElement.h"
      20             : #include "nsIDocument.h"
      21             : #include "nsContentUtils.h"
      22             : #include "nsIPresShell.h"
      23             : #include "nsIPresShellInlines.h"
      24             : #include "nsIXMLContentSink.h"
      25             : #include "nsContentCID.h"
      26             : #include "mozilla/dom/XMLDocument.h"
      27             : #include "nsIStreamListener.h"
      28             : #include "ChildIterator.h"
      29             : #include "nsITimer.h"
      30             : 
      31             : #include "nsXBLBinding.h"
      32             : #include "nsXBLPrototypeBinding.h"
      33             : #include "nsXBLDocumentInfo.h"
      34             : #include "mozilla/dom/XBLChildrenElement.h"
      35             : 
      36             : #include "nsIStyleRuleProcessor.h"
      37             : #include "nsRuleProcessorData.h"
      38             : #include "nsIWeakReference.h"
      39             : 
      40             : #include "nsWrapperCacheInlines.h"
      41             : #include "nsIXPConnect.h"
      42             : #include "nsDOMCID.h"
      43             : #include "nsIScriptGlobalObject.h"
      44             : #include "nsTHashtable.h"
      45             : 
      46             : #include "nsIScriptContext.h"
      47             : #include "xpcpublic.h"
      48             : #include "jswrapper.h"
      49             : 
      50             : #include "nsThreadUtils.h"
      51             : #include "mozilla/dom/NodeListBinding.h"
      52             : #include "mozilla/dom/ScriptSettings.h"
      53             : #include "mozilla/Unused.h"
      54             : 
      55             : using namespace mozilla;
      56             : using namespace mozilla::dom;
      57             : 
      58             : // Implement our nsISupports methods
      59             : 
      60             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsBindingManager)
      61             : 
      62           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsBindingManager)
      63           0 :   tmp->mDestroyed = true;
      64             : 
      65           0 :   if (tmp->mBoundContentSet)
      66           0 :     tmp->mBoundContentSet->Clear();
      67             : 
      68           0 :   if (tmp->mDocumentTable)
      69           0 :     tmp->mDocumentTable->Clear();
      70             : 
      71           0 :   if (tmp->mLoadingDocTable)
      72           0 :     tmp->mLoadingDocTable->Clear();
      73             : 
      74           0 :   if (tmp->mWrapperTable) {
      75           0 :     tmp->mWrapperTable->Clear();
      76           0 :     tmp->mWrapperTable = nullptr;
      77             :   }
      78             : 
      79           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAttachedStack)
      80             : 
      81           0 :   if (tmp->mProcessAttachedQueueEvent) {
      82           0 :     tmp->mProcessAttachedQueueEvent->Revoke();
      83             :   }
      84           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      85             : 
      86             : 
      87           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBindingManager)
      88             :   // The hashes keyed on nsIContent are traversed from the nsIContent itself.
      89           0 :   if (tmp->mDocumentTable) {
      90           0 :     for (auto iter = tmp->mDocumentTable->Iter(); !iter.Done(); iter.Next()) {
      91           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDocumentTable value");
      92           0 :       cb.NoteXPCOMChild(iter.UserData());
      93             :     }
      94             :   }
      95           0 :   if (tmp->mLoadingDocTable) {
      96           0 :     for (auto iter = tmp->mLoadingDocTable->Iter(); !iter.Done(); iter.Next()) {
      97           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mLoadingDocTable value");
      98           0 :       cb.NoteXPCOMChild(iter.UserData());
      99             :     }
     100             :   }
     101           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAttachedStack)
     102             :   // No need to traverse mProcessAttachedQueueEvent, since it'll just
     103             :   // fire at some point or become revoke and drop its ref to us.
     104           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     105             : 
     106          55 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsBindingManager)
     107           0 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
     108           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     109           0 : NS_INTERFACE_MAP_END
     110             : 
     111         101 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBindingManager)
     112          22 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBindingManager)
     113             : 
     114             : // Constructors/Destructors
     115          55 : nsBindingManager::nsBindingManager(nsIDocument* aDocument)
     116             :   : mProcessingAttachedStack(false),
     117             :     mDestroyed(false),
     118             :     mAttachedStackSizeOnOutermost(0),
     119          55 :     mDocument(aDocument)
     120             : {
     121          55 : }
     122             : 
     123           0 : nsBindingManager::~nsBindingManager(void)
     124             : {
     125           0 :   mDestroyed = true;
     126           0 : }
     127             : 
     128             : nsXBLBinding*
     129         958 : nsBindingManager::GetBindingWithContent(const nsIContent* aContent)
     130             : {
     131         958 :   nsXBLBinding* binding = aContent ? aContent->GetXBLBinding() : nullptr;
     132         958 :   return binding ? binding->GetBindingWithContent() : nullptr;
     133             : }
     134             : 
     135             : void
     136         272 : nsBindingManager::AddBoundContent(nsIContent* aContent)
     137             : {
     138         272 :   if (!mBoundContentSet) {
     139           3 :     mBoundContentSet = new nsTHashtable<nsRefPtrHashKey<nsIContent> >;
     140             :   }
     141         272 :   mBoundContentSet->PutEntry(aContent);
     142         272 : }
     143             : 
     144             : void
     145          12 : nsBindingManager::RemoveBoundContent(nsIContent* aContent)
     146             : {
     147          12 :   if (mBoundContentSet) {
     148          12 :     mBoundContentSet->RemoveEntry(aContent);
     149             :   }
     150             : 
     151             :   // The death of the bindings means the death of the JS wrapper.
     152          12 :   SetWrappedJS(aContent, nullptr);
     153          12 : }
     154             : 
     155             : nsIXPConnectWrappedJS*
     156         351 : nsBindingManager::GetWrappedJS(nsIContent* aContent)
     157             : {
     158         351 :   if (!mWrapperTable) {
     159         198 :     return nullptr;
     160             :   }
     161             : 
     162         153 :   if (!aContent || !aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
     163           0 :     return nullptr;
     164             :   }
     165             : 
     166         153 :   return mWrapperTable->GetWeak(aContent);
     167             : }
     168             : 
     169             : nsresult
     170          30 : nsBindingManager::SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aWrappedJS)
     171             : {
     172          30 :   if (mDestroyed) {
     173           0 :     return NS_OK;
     174             :   }
     175             : 
     176          30 :   if (aWrappedJS) {
     177             :     // lazily create the table, but only when adding elements
     178          18 :     if (!mWrapperTable) {
     179           1 :       mWrapperTable = new WrapperHashtable();
     180             :     }
     181          18 :     aContent->SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
     182             : 
     183          18 :     NS_ASSERTION(aContent, "key must be non-null");
     184          18 :     if (!aContent) return NS_ERROR_INVALID_ARG;
     185             : 
     186          18 :     mWrapperTable->Put(aContent, aWrappedJS);
     187             : 
     188          18 :     return NS_OK;
     189             :   }
     190             : 
     191             :   // no value, so remove the key from the table
     192          12 :   if (mWrapperTable) {
     193          12 :     mWrapperTable->Remove(aContent);
     194             :   }
     195             : 
     196          12 :   return NS_OK;
     197             : }
     198             : 
     199             : void
     200          12 : nsBindingManager::RemovedFromDocumentInternal(nsIContent* aContent,
     201             :                                               nsIDocument* aOldDocument,
     202             :                                               DestructorHandling aDestructorHandling)
     203             : {
     204          12 :   NS_PRECONDITION(aOldDocument != nullptr, "no old document");
     205             : 
     206          24 :   RefPtr<nsXBLBinding> binding = aContent->GetXBLBinding();
     207          12 :   if (binding) {
     208             :     // The binding manager may have been destroyed before a runnable
     209             :     // has had a chance to reach this point. If so, we bail out on calling
     210             :     // BindingDetached (which may invoke a XBL destructor) and
     211             :     // ChangeDocument, but we still want to clear out the binding
     212             :     // and insertion parent that may hold references.
     213           7 :     if (!mDestroyed && aDestructorHandling == eRunDtor) {
     214           7 :       binding->PrototypeBinding()->BindingDetached(binding->GetBoundElement());
     215           7 :       binding->ChangeDocument(aOldDocument, nullptr);
     216             :     }
     217             : 
     218           7 :     aContent->SetXBLBinding(nullptr, this);
     219             :   }
     220             : 
     221             :   // Clear out insertion parent and content lists.
     222          12 :   aContent->SetXBLInsertionParent(nullptr);
     223          12 : }
     224             : 
     225             : nsIAtom*
     226         766 : nsBindingManager::ResolveTag(nsIContent* aContent, int32_t* aNameSpaceID)
     227             : {
     228         766 :   nsXBLBinding *binding = aContent->GetXBLBinding();
     229             : 
     230         766 :   if (binding) {
     231         432 :     nsIAtom* base = binding->GetBaseTag(aNameSpaceID);
     232             : 
     233         432 :     if (base) {
     234          86 :       return base;
     235             :     }
     236             :   }
     237             : 
     238         680 :   *aNameSpaceID = aContent->GetNameSpaceID();
     239         680 :   return aContent->NodeInfo()->NameAtom();
     240             : }
     241             : 
     242             : nsresult
     243           0 : nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent,
     244             :                                        nsIDOMNodeList** aResult)
     245             : {
     246           0 :   NS_IF_ADDREF(*aResult = GetAnonymousNodesFor(aContent));
     247           0 :   return NS_OK;
     248             : }
     249             : 
     250             : nsINodeList*
     251          19 : nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent)
     252             : {
     253          19 :   nsXBLBinding* binding = GetBindingWithContent(aContent);
     254          19 :   return binding ? binding->GetAnonymousNodeList() : nullptr;
     255             : }
     256             : 
     257             : nsresult
     258           0 : nsBindingManager::ClearBinding(Element* aElement)
     259             : {
     260             :   // Hold a ref to the binding so it won't die when we remove it from our table
     261             :   RefPtr<nsXBLBinding> binding =
     262           0 :     aElement ? aElement->GetXBLBinding() : nullptr;
     263             : 
     264           0 :   if (!binding) {
     265           0 :     return NS_OK;
     266             :   }
     267             : 
     268             :   // For now we can only handle removing a binding if it's the only one
     269           0 :   NS_ENSURE_FALSE(binding->GetBaseBinding(), NS_ERROR_FAILURE);
     270             : 
     271             :   // Hold strong ref in case removing the binding tries to close the
     272             :   // window or something.
     273             :   // XXXbz should that be ownerdoc?  Wouldn't we need a ref to the
     274             :   // currentdoc too?  What's the one that should be passed to
     275             :   // ChangeDocument?
     276           0 :   nsCOMPtr<nsIDocument> doc = aElement->OwnerDoc();
     277             : 
     278             :   // Finally remove the binding...
     279             :   // XXXbz this doesn't remove the implementation!  Should fix!  Until
     280             :   // then we need the explicit UnhookEventHandlers here.
     281           0 :   binding->UnhookEventHandlers();
     282           0 :   binding->ChangeDocument(doc, nullptr);
     283           0 :   aElement->SetXBLBinding(nullptr, this);
     284           0 :   binding->MarkForDeath();
     285             : 
     286             :   // ...and recreate its frames. We need to do this since the frames may have
     287             :   // been removed and style may have changed due to the removal of the
     288             :   // anonymous children.
     289             :   // XXXbz this should be using the current doc (if any), not the owner doc.
     290           0 :   nsIPresShell *presShell = doc->GetShell();
     291           0 :   NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
     292             : 
     293           0 :   presShell->PostRecreateFramesFor(aElement);
     294           0 :   return NS_OK;
     295             : }
     296             : 
     297             : nsresult
     298           0 : nsBindingManager::LoadBindingDocument(nsIDocument* aBoundDoc,
     299             :                                       nsIURI* aURL,
     300             :                                       nsIPrincipal* aOriginPrincipal)
     301             : {
     302           0 :   NS_PRECONDITION(aURL, "Must have a URI to load!");
     303             : 
     304             :   // First we need to load our binding.
     305           0 :   nsXBLService* xblService = nsXBLService::GetInstance();
     306           0 :   if (!xblService)
     307           0 :     return NS_ERROR_FAILURE;
     308             : 
     309             :   // Load the binding doc.
     310           0 :   RefPtr<nsXBLDocumentInfo> info;
     311           0 :   xblService->LoadBindingDocumentInfo(nullptr, aBoundDoc, aURL,
     312             :                                       aOriginPrincipal, true,
     313           0 :                                       getter_AddRefs(info));
     314           0 :   if (!info)
     315           0 :     return NS_ERROR_FAILURE;
     316             : 
     317           0 :   return NS_OK;
     318             : }
     319             : 
     320             : void
     321          12 : nsBindingManager::RemoveFromAttachedQueue(nsXBLBinding* aBinding)
     322             : {
     323             :   // Don't remove items here as that could mess up an executing
     324             :   // ProcessAttachedQueue. Instead, null the entry in the queue.
     325          12 :   size_t index = mAttachedStack.IndexOf(aBinding);
     326          12 :   if (index != mAttachedStack.NoIndex) {
     327           0 :     mAttachedStack[index] = nullptr;
     328             :   }
     329          12 : }
     330             : 
     331             : nsresult
     332         238 : nsBindingManager::AddToAttachedQueue(nsXBLBinding* aBinding)
     333             : {
     334         238 :   mAttachedStack.AppendElement(aBinding);
     335             : 
     336             :   // If we're in the middle of processing our queue already, don't
     337             :   // bother posting the event.
     338         238 :   if (!mProcessingAttachedStack && !mProcessAttachedQueueEvent) {
     339           6 :     PostProcessAttachedQueueEvent();
     340             :   }
     341             : 
     342             :   // Make sure that flushes will flush out the new items as needed.
     343         238 :   if (nsIPresShell* shell = mDocument->GetShell()) {
     344         238 :     shell->SetNeedStyleFlush();
     345             :   }
     346             : 
     347         238 :   return NS_OK;
     348             : 
     349             : }
     350             : 
     351             : void
     352           6 : nsBindingManager::PostProcessAttachedQueueEvent()
     353             : {
     354           6 :   MOZ_ASSERT(NS_IsMainThread());
     355           6 :   if (!mDocument) {
     356           0 :     return;
     357             :   }
     358             :   mProcessAttachedQueueEvent =
     359          12 :     NewRunnableMethod("nsBindingManager::DoProcessAttachedQueue",
     360           6 :                       this, &nsBindingManager::DoProcessAttachedQueue);
     361           6 :   nsresult rv = mDocument->EventTargetFor(TaskCategory::Other)->Dispatch(do_AddRef(mProcessAttachedQueueEvent));
     362           6 :   if (NS_SUCCEEDED(rv)) {
     363           6 :     mDocument->BlockOnload();
     364             :   }
     365             : }
     366             : 
     367             : // static
     368             : void
     369           0 : nsBindingManager::PostPAQEventCallback(nsITimer* aTimer, void* aClosure)
     370             : {
     371             :   RefPtr<nsBindingManager> mgr =
     372           0 :     already_AddRefed<nsBindingManager>(static_cast<nsBindingManager*>(aClosure));
     373           0 :   mgr->PostProcessAttachedQueueEvent();
     374           0 :   NS_RELEASE(aTimer);
     375           0 : }
     376             : 
     377             : void
     378           6 : nsBindingManager::DoProcessAttachedQueue()
     379             : {
     380           6 :   if (!mProcessingAttachedStack) {
     381           6 :     ProcessAttachedQueue();
     382             : 
     383           6 :     NS_ASSERTION(mAttachedStack.Length() == 0,
     384             :                "Shouldn't have pending bindings!");
     385             : 
     386           6 :     mProcessAttachedQueueEvent = nullptr;
     387             :   } else {
     388             :     // Someone's doing event processing from inside a constructor.
     389             :     // They're evil, but we'll fight back!  Just poll on them being
     390             :     // done and repost the attached queue event.
     391             :     //
     392             :     // But don't poll in a tight loop -- otherwise we keep the Gecko
     393             :     // event loop non-empty and trigger bug 1021240 on OS X.
     394           0 :     nsresult rv = NS_ERROR_FAILURE;
     395           0 :     nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
     396           0 :     if (timer) {
     397           0 :       rv = timer->InitWithNamedFuncCallback(
     398             :         PostPAQEventCallback,
     399             :         this,
     400             :         100,
     401             :         nsITimer::TYPE_ONE_SHOT,
     402           0 :         "nsBindingManager::DoProcessAttachedQueue");
     403             :     }
     404           0 :     if (NS_SUCCEEDED(rv)) {
     405           0 :       NS_ADDREF_THIS();
     406             :       // We drop our reference to the timer here, since the timer callback is
     407             :       // responsible for releasing the object.
     408           0 :       Unused << timer.forget().take();
     409             :     }
     410             :   }
     411             : 
     412             :   // No matter what, unblock onload for the event that's fired.
     413           6 :   if (mDocument) {
     414             :     // Hold a strong reference while calling UnblockOnload since that might
     415             :     // run script.
     416          12 :     nsCOMPtr<nsIDocument> doc = mDocument;
     417           6 :     doc->UnblockOnload(true);
     418             :   }
     419           6 : }
     420             : 
     421             : void
     422          10 : nsBindingManager::ProcessAttachedQueueInternal(uint32_t aSkipSize)
     423             : {
     424          10 :   mProcessingAttachedStack = true;
     425             : 
     426             :   // Excute constructors. Do this from high index to low
     427         486 :   while (mAttachedStack.Length() > aSkipSize) {
     428         238 :     uint32_t lastItem = mAttachedStack.Length() - 1;
     429         476 :     RefPtr<nsXBLBinding> binding = mAttachedStack.ElementAt(lastItem);
     430         238 :     mAttachedStack.RemoveElementAt(lastItem);
     431         238 :     if (binding) {
     432         238 :       binding->ExecuteAttachedHandler();
     433             :     }
     434             :   }
     435             : 
     436             :   // If NodeWillBeDestroyed has run we don't want to clobber
     437             :   // mProcessingAttachedStack set there.
     438          10 :   if (mDocument) {
     439          10 :     mProcessingAttachedStack = false;
     440             :   }
     441             : 
     442          10 :   NS_ASSERTION(mAttachedStack.Length() == aSkipSize, "How did we get here?");
     443             : 
     444          10 :   mAttachedStack.Compact();
     445          10 : }
     446             : 
     447             : // Keep bindings and bound elements alive while executing detached handlers.
     448             : void
     449           4 : nsBindingManager::ExecuteDetachedHandlers()
     450             : {
     451             :   // Walk our hashtable of bindings.
     452           4 :   if (!mBoundContentSet) {
     453           4 :     return;
     454             :   }
     455             : 
     456           0 :   nsCOMArray<nsIContent> boundElements;
     457           0 :   nsBindingList bindings;
     458             : 
     459           0 :   for (auto iter = mBoundContentSet->Iter(); !iter.Done(); iter.Next()) {
     460           0 :     nsXBLBinding* binding = iter.Get()->GetKey()->GetXBLBinding();
     461           0 :     if (binding && bindings.AppendElement(binding)) {
     462           0 :       if (!boundElements.AppendObject(binding->GetBoundElement())) {
     463           0 :         bindings.RemoveElementAt(bindings.Length() - 1);
     464             :       }
     465             :     }
     466             :   }
     467             : 
     468           0 :   uint32_t i, count = bindings.Length();
     469           0 :   for (i = 0; i < count; ++i) {
     470           0 :     bindings[i]->ExecuteDetachedHandler();
     471             :   }
     472             : }
     473             : 
     474             : nsresult
     475         634 : nsBindingManager::PutXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo)
     476             : {
     477         634 :   NS_PRECONDITION(aDocumentInfo, "Must have a non-null documentinfo!");
     478             : 
     479         634 :   if (!mDocumentTable) {
     480           4 :     mDocumentTable = new nsRefPtrHashtable<nsURIHashKey,nsXBLDocumentInfo>();
     481             :   }
     482             : 
     483         634 :   mDocumentTable->Put(aDocumentInfo->DocumentURI(), aDocumentInfo);
     484             : 
     485         634 :   return NS_OK;
     486             : }
     487             : 
     488             : void
     489           1 : nsBindingManager::RemoveXBLDocumentInfo(nsXBLDocumentInfo* aDocumentInfo)
     490             : {
     491           1 :   if (mDocumentTable) {
     492           1 :     mDocumentTable->Remove(aDocumentInfo->DocumentURI());
     493             :   }
     494           1 : }
     495             : 
     496             : nsXBLDocumentInfo*
     497         634 : nsBindingManager::GetXBLDocumentInfo(nsIURI* aURL)
     498             : {
     499         634 :   if (!mDocumentTable)
     500           3 :     return nullptr;
     501             : 
     502         631 :   return mDocumentTable->GetWeak(aURL);
     503             : }
     504             : 
     505             : nsresult
     506           0 : nsBindingManager::PutLoadingDocListener(nsIURI* aURL, nsIStreamListener* aListener)
     507             : {
     508           0 :   NS_PRECONDITION(aListener, "Must have a non-null listener!");
     509             : 
     510           0 :   if (!mLoadingDocTable) {
     511             :     mLoadingDocTable =
     512           0 :       new nsInterfaceHashtable<nsURIHashKey,nsIStreamListener>();
     513             :   }
     514           0 :   mLoadingDocTable->Put(aURL, aListener);
     515             : 
     516           0 :   return NS_OK;
     517             : }
     518             : 
     519             : nsIStreamListener*
     520          23 : nsBindingManager::GetLoadingDocListener(nsIURI* aURL)
     521             : {
     522          23 :   if (!mLoadingDocTable)
     523          23 :     return nullptr;
     524             : 
     525           0 :   return mLoadingDocTable->GetWeak(aURL);
     526             : }
     527             : 
     528             : void
     529           0 : nsBindingManager::RemoveLoadingDocListener(nsIURI* aURL)
     530             : {
     531           0 :   if (mLoadingDocTable) {
     532           0 :     mLoadingDocTable->Remove(aURL);
     533             :   }
     534           0 : }
     535             : 
     536             : void
     537           0 : nsBindingManager::FlushSkinBindings()
     538             : {
     539           0 :   if (!mBoundContentSet) {
     540           0 :     return;
     541             :   }
     542             : 
     543           0 :   for (auto iter = mBoundContentSet->Iter(); !iter.Done(); iter.Next()) {
     544           0 :     nsXBLBinding* binding = iter.Get()->GetKey()->GetXBLBinding();
     545             : 
     546           0 :     if (binding->MarkedForDeath()) {
     547           0 :       continue;
     548             :     }
     549             : 
     550           0 :     nsAutoCString path;
     551           0 :     binding->PrototypeBinding()->DocURI()->GetPath(path);
     552             : 
     553           0 :     if (!strncmp(path.get(), "/skin", 5)) {
     554           0 :       binding->MarkForDeath();
     555             :     }
     556             :   }
     557             : }
     558             : 
     559             : // Used below to protect from recurring in QI calls through XPConnect.
     560             : struct AntiRecursionData {
     561             :   nsIContent* element;
     562             :   REFNSIID iid;
     563             :   AntiRecursionData* next;
     564             : 
     565          48 :   AntiRecursionData(nsIContent* aElement,
     566             :                     REFNSIID aIID,
     567             :                     AntiRecursionData* aNext)
     568          48 :     : element(aElement), iid(aIID), next(aNext) {}
     569             : };
     570             : 
     571             : nsresult
     572         210 : nsBindingManager::GetBindingImplementation(nsIContent* aContent, REFNSIID aIID,
     573             :                                            void** aResult)
     574             : {
     575         210 :   *aResult = nullptr;
     576         210 :   nsXBLBinding *binding = aContent ? aContent->GetXBLBinding() : nullptr;
     577         210 :   if (binding) {
     578             :     // The binding should not be asked for nsISupports
     579         140 :     NS_ASSERTION(!aIID.Equals(NS_GET_IID(nsISupports)), "Asking a binding for nsISupports");
     580         140 :     if (binding->ImplementsInterface(aIID)) {
     581         132 :       nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = GetWrappedJS(aContent);
     582             : 
     583          66 :       if (wrappedJS) {
     584             :         // Protect from recurring in QI calls through XPConnect.
     585             :         // This can happen when a second binding is being resolved.
     586             :         // At that point a wrappedJS exists, but it doesn't yet know about
     587             :         // the iid we are asking for. So, without this protection,
     588             :         // AggregatedQueryInterface would end up recurring back into itself
     589             :         // through this code.
     590             :         //
     591             :         // With this protection, when we detect the recursion we return
     592             :         // NS_NOINTERFACE in the inner call. The outer call will then fall
     593             :         // through (see below) and build a new chained wrappedJS for the iid.
     594             :         //
     595             :         // We're careful to not assume that only one direct nesting can occur
     596             :         // because there is a call into JS in the middle and we can't assume
     597             :         // that this code won't be reached by some more complex nesting path.
     598             :         //
     599             :         // NOTE: We *assume* this is single threaded, so we can use a
     600             :         // static linked list to do the check.
     601             : 
     602             :         static AntiRecursionData* list = nullptr;
     603             : 
     604          49 :         for (AntiRecursionData* p = list; p; p = p->next) {
     605           1 :           if (p->element == aContent && p->iid.Equals(aIID)) {
     606           1 :             *aResult = nullptr;
     607          49 :             return NS_NOINTERFACE;
     608             :           }
     609             :         }
     610             : 
     611          48 :         AntiRecursionData item(aContent, aIID, list);
     612          48 :         list = &item;
     613             : 
     614          48 :         nsresult rv = wrappedJS->AggregatedQueryInterface(aIID, aResult);
     615             : 
     616          48 :         list = item.next;
     617             : 
     618          48 :         if (*aResult)
     619          47 :           return rv;
     620             : 
     621             :         // No result was found, so this must be another XBL interface.
     622             :         // Fall through to create a new wrapper.
     623             :       }
     624             : 
     625             :       // We have never made a wrapper for this implementation.
     626             :       // Create an XPC wrapper for the script object and hand it back.
     627          36 :       AutoJSAPI jsapi;
     628          18 :       jsapi.Init();
     629          18 :       JSContext* cx = jsapi.cx();
     630             : 
     631          18 :       nsIXPConnect *xpConnect = nsContentUtils::XPConnect();
     632             : 
     633          36 :       JS::Rooted<JSObject*> jsobj(cx, aContent->GetWrapper());
     634          18 :       NS_ENSURE_TRUE(jsobj, NS_NOINTERFACE);
     635             : 
     636             :       // If we're using an XBL scope, we need to use the Xray view to the bound
     637             :       // content in order to view the full array of methods defined in the
     638             :       // binding, some of which may not be exposed on the prototype of
     639             :       // untrusted content. We don't need to consider add-on scopes here
     640             :       // because they're chrome-only and no Xrays are involved.
     641             :       //
     642             :       // If there's no separate XBL scope, or if the reflector itself lives in
     643             :       // the XBL scope, we'll end up with the global of the reflector.
     644          36 :       JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScopeOrGlobal(cx, jsobj));
     645          18 :       NS_ENSURE_TRUE(xblScope, NS_ERROR_UNEXPECTED);
     646          36 :       JSAutoCompartment ac(cx, xblScope);
     647          18 :       bool ok = JS_WrapObject(cx, &jsobj);
     648          18 :       NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
     649          18 :       MOZ_ASSERT_IF(js::IsWrapper(jsobj), xpc::IsXrayWrapper(jsobj));
     650             : 
     651          18 :       nsresult rv = xpConnect->WrapJSAggregatedToNative(aContent, cx,
     652          36 :                                                         jsobj, aIID, aResult);
     653          18 :       if (NS_FAILED(rv))
     654           0 :         return rv;
     655             : 
     656             :       // We successfully created a wrapper.  We will own this wrapper for as long as the binding remains
     657             :       // alive.  At the time the binding is cleared out of the bindingManager, we will remove the wrapper
     658             :       // from the bindingManager as well.
     659          18 :       nsISupports* supp = static_cast<nsISupports*>(*aResult);
     660          18 :       wrappedJS = do_QueryInterface(supp);
     661          18 :       SetWrappedJS(aContent, wrappedJS);
     662             : 
     663          18 :       return rv;
     664             :     }
     665             :   }
     666             : 
     667         144 :   *aResult = nullptr;
     668         144 :   return NS_NOINTERFACE;
     669             : }
     670             : 
     671             : nsresult
     672        4488 : nsBindingManager::WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc,
     673             :                             ElementDependentRuleProcessorData* aData,
     674             :                             bool* aCutOffInheritance)
     675             : {
     676        4488 :   *aCutOffInheritance = false;
     677             : 
     678        4488 :   NS_ASSERTION(aData->mElement, "How did that happen?");
     679             : 
     680             :   // Walk the binding scope chain, starting with the binding attached to our
     681             :   // content, up till we run out of scopes or we get cut off.
     682        4488 :   nsIContent *content = aData->mElement;
     683             : 
     684        1850 :   do {
     685        6338 :     nsXBLBinding *binding = content->GetXBLBinding();
     686        6338 :     if (binding) {
     687        3603 :       binding->WalkRules(aFunc, aData);
     688             :       // If we're not looking at our original content, allow the binding to cut
     689             :       // off style inheritance
     690        3603 :       if (content != aData->mElement) {
     691        1804 :         if (!binding->InheritsStyle()) {
     692             :           // Go no further; we're not inheriting style from anything above here
     693           0 :           break;
     694             :         }
     695             :       }
     696             :     }
     697             : 
     698        6338 :     if (content->IsRootOfNativeAnonymousSubtree()) {
     699         367 :       break; // Deliberately cut off style inheritance here.
     700             :     }
     701             : 
     702        5971 :     content = content->GetBindingParent();
     703        5971 :   } while (content);
     704             : 
     705             :   // If "content" is non-null that means we cut off inheritance at some point
     706             :   // in the loop.
     707        4488 :   *aCutOffInheritance = (content != nullptr);
     708             : 
     709        4488 :   return NS_OK;
     710             : }
     711             : 
     712             : typedef nsTHashtable<nsPtrHashKey<nsIStyleRuleProcessor> > RuleProcessorSet;
     713             : 
     714             : static RuleProcessorSet*
     715           5 : GetContentSetRuleProcessors(nsTHashtable<nsRefPtrHashKey<nsIContent>>* aContentSet)
     716             : {
     717           5 :   RuleProcessorSet* set = nullptr;
     718             : 
     719         962 :   for (auto iter = aContentSet->Iter(); !iter.Done(); iter.Next()) {
     720         957 :     nsIContent* boundContent = iter.Get()->GetKey();
     721        3184 :     for (nsXBLBinding* binding = boundContent->GetXBLBinding(); binding;
     722             :          binding = binding->GetBaseBinding()) {
     723             :       nsIStyleRuleProcessor* ruleProc =
     724        2227 :         binding->PrototypeBinding()->GetRuleProcessor();
     725        2227 :       if (ruleProc) {
     726         596 :         if (!set) {
     727           4 :           set = new RuleProcessorSet;
     728             :         }
     729         596 :         set->PutEntry(ruleProc);
     730             :       }
     731             :     }
     732             :   }
     733             : 
     734           5 :   return set;
     735             : }
     736             : 
     737             : void
     738           2 : nsBindingManager::WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc,
     739             :                                ElementDependentRuleProcessorData* aData)
     740             : {
     741           2 :   if (!mBoundContentSet) {
     742           1 :     return;
     743             :   }
     744             : 
     745           3 :   nsAutoPtr<RuleProcessorSet> set;
     746           2 :   set = GetContentSetRuleProcessors(mBoundContentSet);
     747           2 :   if (!set) {
     748           1 :     return;
     749             :   }
     750             : 
     751          24 :   for (auto iter = set->Iter(); !iter.Done(); iter.Next()) {
     752          23 :     nsIStyleRuleProcessor* ruleProcessor = iter.Get()->GetKey();
     753          23 :     (*(aFunc))(ruleProcessor, aData);
     754             :   }
     755             : }
     756             : 
     757             : nsresult
     758          21 : nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext,
     759             :                                         bool* aRulesChanged)
     760             : {
     761          21 :   *aRulesChanged = false;
     762          21 :   if (!mBoundContentSet) {
     763          18 :     return NS_OK;
     764             :   }
     765             : 
     766           6 :   nsAutoPtr<RuleProcessorSet> set;
     767           3 :   set = GetContentSetRuleProcessors(mBoundContentSet);
     768           3 :   if (!set) {
     769           0 :     return NS_OK;
     770             :   }
     771             : 
     772          72 :   for (auto iter = set->Iter(); !iter.Done(); iter.Next()) {
     773          69 :     nsIStyleRuleProcessor* ruleProcessor = iter.Get()->GetKey();
     774          69 :     bool thisChanged = ruleProcessor->MediumFeaturesChanged(aPresContext);
     775          69 :     *aRulesChanged = *aRulesChanged || thisChanged;
     776             :   }
     777             : 
     778           3 :   return NS_OK;
     779             : }
     780             : 
     781             : void
     782           0 : nsBindingManager::AppendAllSheets(nsTArray<StyleSheet*>& aArray)
     783             : {
     784           0 :   if (!mBoundContentSet) {
     785           0 :     return;
     786             :   }
     787             : 
     788           0 :   for (auto iter = mBoundContentSet->Iter(); !iter.Done(); iter.Next()) {
     789           0 :     nsIContent* boundContent = iter.Get()->GetKey();
     790           0 :     for (nsXBLBinding* binding = boundContent->GetXBLBinding(); binding;
     791             :          binding = binding->GetBaseBinding()) {
     792           0 :       binding->PrototypeBinding()->AppendStyleSheetsTo(aArray);
     793             :     }
     794             :   }
     795             : }
     796             : 
     797             : static void
     798           0 : InsertAppendedContent(XBLChildrenElement* aPoint,
     799             :                       nsIContent* aFirstNewContent)
     800             : {
     801             :   int32_t insertionIndex;
     802           0 :   if (nsIContent* prevSibling = aFirstNewContent->GetPreviousSibling()) {
     803             :     // If we have a previous sibling, then it must already be in aPoint. Find
     804             :     // it and insert after it.
     805           0 :     insertionIndex = aPoint->IndexOfInsertedChild(prevSibling);
     806           0 :     MOZ_ASSERT(insertionIndex != -1);
     807             : 
     808             :     // Our insertion index is one after our previous sibling's index.
     809           0 :     ++insertionIndex;
     810             :   } else {
     811             :     // Otherwise, we append.
     812             :     // TODO This is wrong for nested insertion points. In that case, we need to
     813             :     // keep track of the right index to insert into.
     814           0 :     insertionIndex = aPoint->InsertedChildrenLength();
     815             :   }
     816             : 
     817             :   // Do the inserting.
     818           0 :   for (nsIContent* currentChild = aFirstNewContent;
     819           0 :        currentChild;
     820           0 :        currentChild = currentChild->GetNextSibling()) {
     821           0 :     aPoint->InsertInsertedChildAt(currentChild, insertionIndex++);
     822             :   }
     823           0 : }
     824             : 
     825             : void
     826         143 : nsBindingManager::ContentAppended(nsIDocument* aDocument,
     827             :                                   nsIContent* aContainer,
     828             :                                   nsIContent* aFirstNewContent,
     829             :                                   int32_t     aNewIndexInContainer)
     830             : {
     831         143 :   if (aNewIndexInContainer == -1) {
     832           0 :     return;
     833             :   }
     834             : 
     835             :   // Try to find insertion points for all the new kids.
     836         143 :   XBLChildrenElement* point = nullptr;
     837         143 :   nsIContent* parent = aContainer;
     838             : 
     839             :   // Handle appending of default content.
     840         143 :   if (parent && parent->IsActiveChildrenElement()) {
     841           0 :     XBLChildrenElement* childrenEl = static_cast<XBLChildrenElement*>(parent);
     842           0 :     if (childrenEl->HasInsertedChildren()) {
     843             :       // Appending default content that isn't being used. Ignore.
     844           0 :       return;
     845             :     }
     846             : 
     847           0 :     childrenEl->MaybeSetupDefaultContent();
     848           0 :     parent = childrenEl->GetParent();
     849             :   }
     850             : 
     851         143 :   bool first = true;
     852           2 :   do {
     853         145 :     nsXBLBinding* binding = GetBindingWithContent(parent);
     854         145 :     if (!binding) {
     855         138 :       break;
     856             :     }
     857             : 
     858           7 :     if (binding->HasFilteredInsertionPoints()) {
     859             :       // There are filtered insertion points involved, handle each child
     860             :       // separately.
     861             :       // We could optimize this in the case when we've nested a few levels
     862             :       // deep already, without hitting bindings that have filtered insertion
     863             :       // points.
     864           4 :       int32_t currentIndex = aNewIndexInContainer;
     865           8 :       for (nsIContent* currentChild = aFirstNewContent; currentChild;
     866           4 :            currentChild = currentChild->GetNextSibling()) {
     867           4 :         HandleChildInsertion(aContainer, currentChild,
     868           8 :                              currentIndex++, true);
     869             :       }
     870             : 
     871           4 :       return;
     872             :     }
     873             : 
     874           3 :     point = binding->GetDefaultInsertionPoint();
     875           3 :     if (!point) {
     876           0 :       break;
     877             :     }
     878             : 
     879             :     // Even though we're in ContentAppended, nested insertion points force us
     880             :     // to deal with this append as an insertion except in the outermost
     881             :     // binding.
     882           3 :     if (first) {
     883           3 :       first = false;
     884          19 :       for (nsIContent* child = aFirstNewContent; child;
     885          16 :            child = child->GetNextSibling()) {
     886          16 :         point->AppendInsertedChild(child);
     887             :       }
     888             :     } else {
     889           0 :       InsertAppendedContent(point, aFirstNewContent);
     890             :     }
     891             : 
     892           3 :     nsIContent* newParent = point->GetParent();
     893           3 :     if (newParent == parent) {
     894           1 :       break;
     895             :     }
     896           2 :     parent = newParent;
     897           2 :   } while (parent);
     898             : }
     899             : 
     900             : void
     901          71 : nsBindingManager::ContentInserted(nsIDocument* aDocument,
     902             :                                   nsIContent* aContainer,
     903             :                                   nsIContent* aChild,
     904             :                                   int32_t aIndexInContainer)
     905             : {
     906          71 :   if (aIndexInContainer == -1) {
     907           0 :     return;
     908             :   }
     909             : 
     910          71 :   HandleChildInsertion(aContainer, aChild, aIndexInContainer, false);
     911             : }
     912             : 
     913             : void
     914          47 : nsBindingManager::ContentRemoved(nsIDocument* aDocument,
     915             :                                  nsIContent* aContainer,
     916             :                                  nsIContent* aChild,
     917             :                                  int32_t aIndexInContainer,
     918             :                                  nsIContent* aPreviousSibling)
     919             : {
     920          47 :   aChild->SetXBLInsertionParent(nullptr);
     921             : 
     922          47 :   XBLChildrenElement* point = nullptr;
     923          47 :   nsIContent* parent = aContainer;
     924             : 
     925             :   // Handle appending of default content.
     926          47 :   if (parent && parent->IsActiveChildrenElement()) {
     927           0 :     XBLChildrenElement* childrenEl = static_cast<XBLChildrenElement*>(parent);
     928           0 :     if (childrenEl->HasInsertedChildren()) {
     929             :       // Removing default content that isn't being used. Ignore.
     930           0 :       return;
     931             :     }
     932             : 
     933           0 :     parent = childrenEl->GetParent();
     934             :   }
     935             : 
     936           2 :   do {
     937          49 :     nsXBLBinding* binding = GetBindingWithContent(parent);
     938          49 :     if (!binding) {
     939             :       // If aChild is XBL content, it might have <xbl:children> elements
     940             :       // somewhere under it. We need to inform those elements that they're no
     941             :       // longer in the tree so they can tell their distributed children that
     942             :       // they're no longer distributed under them.
     943             :       // XXX This is wrong. We need to do far more work to update the parent
     944             :       // binding's list of insertion points and to get the new insertion parent
     945             :       // for the newly-distributed children correct.
     946          47 :       if (aChild->GetBindingParent()) {
     947           5 :         ClearInsertionPointsRecursively(aChild);
     948             :       }
     949          47 :       return;
     950             :     }
     951             : 
     952           2 :     point = binding->FindInsertionPointFor(aChild);
     953           2 :     if (!point) {
     954           0 :       break;
     955             :     }
     956             : 
     957           2 :     point->RemoveInsertedChild(aChild);
     958             : 
     959           2 :     nsIContent* newParent = point->GetParent();
     960           2 :     if (newParent == parent) {
     961           0 :       break;
     962             :     }
     963           2 :     parent = newParent;
     964           2 :   } while (parent);
     965             : }
     966             : 
     967             : void
     968           5 : nsBindingManager::ClearInsertionPointsRecursively(nsIContent* aContent)
     969             : {
     970           5 :   if (aContent->NodeInfo()->Equals(nsGkAtoms::children, kNameSpaceID_XBL)) {
     971           0 :     static_cast<XBLChildrenElement*>(aContent)->ClearInsertedChildren();
     972             :   }
     973             : 
     974           5 :   for (nsIContent* child = aContent->GetFirstChild(); child;
     975           0 :        child = child->GetNextSibling()) {
     976           0 :     ClearInsertionPointsRecursively(child);
     977             :   }
     978           5 : }
     979             : 
     980             : void
     981           0 : nsBindingManager::DropDocumentReference()
     982             : {
     983           0 :   mDestroyed = true;
     984             : 
     985             :   // Make sure to not run any more XBL constructors
     986           0 :   mProcessingAttachedStack = true;
     987           0 :   if (mProcessAttachedQueueEvent) {
     988           0 :     mProcessAttachedQueueEvent->Revoke();
     989             :   }
     990             : 
     991           0 :   if (mBoundContentSet) {
     992           0 :     mBoundContentSet->Clear();
     993             :   }
     994             : 
     995           0 :   mDocument = nullptr;
     996           0 : }
     997             : 
     998             : void
     999         432 : nsBindingManager::Traverse(nsIContent *aContent,
    1000             :                            nsCycleCollectionTraversalCallback &cb)
    1001             : {
    1002         717 :   if (!aContent->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
    1003         285 :       !aContent->IsElement()) {
    1004             :     // Don't traverse if content is not in this binding manager.
    1005             :     // We also don't traverse non-elements because there should not
    1006             :     // be bindings (checking the flag alone is not sufficient because
    1007             :     // the flag is also set on children of insertion points that may be
    1008             :     // non-elements).
    1009         147 :     return;
    1010             :   }
    1011             : 
    1012         285 :   if (mBoundContentSet && mBoundContentSet->Contains(aContent)) {
    1013         279 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mBoundContentSet entry");
    1014         279 :     cb.NoteXPCOMChild(aContent);
    1015             :   }
    1016             : 
    1017         285 :   nsIXPConnectWrappedJS *value = GetWrappedJS(aContent);
    1018         285 :   if (value) {
    1019           0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mWrapperTable key");
    1020           0 :     cb.NoteXPCOMChild(aContent);
    1021           0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[via binding manager] mWrapperTable value");
    1022           0 :     cb.NoteXPCOMChild(value);
    1023             :   }
    1024             : }
    1025             : 
    1026             : void
    1027          75 : nsBindingManager::HandleChildInsertion(nsIContent* aContainer,
    1028             :                                        nsIContent* aChild,
    1029             :                                        uint32_t aIndexInContainer,
    1030             :                                        bool aAppend)
    1031             : {
    1032          75 :   NS_PRECONDITION(aChild, "Must have child");
    1033          75 :   NS_PRECONDITION(!aContainer ||
    1034             :                   uint32_t(aContainer->IndexOf(aChild)) == aIndexInContainer,
    1035             :                   "Child not at the right index?");
    1036             : 
    1037          75 :   XBLChildrenElement* point = nullptr;
    1038          75 :   nsIContent* parent = aContainer;
    1039             : 
    1040             :   // Handle insertion of default content.
    1041          75 :   if (parent && parent->IsActiveChildrenElement()) {
    1042           0 :     XBLChildrenElement* childrenEl = static_cast<XBLChildrenElement*>(parent);
    1043           0 :     if (childrenEl->HasInsertedChildren()) {
    1044             :       // Inserting default content that isn't being used. Ignore.
    1045           0 :       return;
    1046             :     }
    1047             : 
    1048           0 :     childrenEl->MaybeSetupDefaultContent();
    1049           0 :     parent = childrenEl->GetParent();
    1050             :   }
    1051             : 
    1052         101 :   while (parent) {
    1053          36 :     nsXBLBinding* binding = GetBindingWithContent(parent);
    1054          36 :     if (!binding) {
    1055          19 :       break;
    1056             :     }
    1057             : 
    1058          17 :     point = binding->FindInsertionPointFor(aChild);
    1059          17 :     if (!point) {
    1060           0 :       break;
    1061             :     }
    1062             : 
    1063             :     // Insert the child into the proper insertion point.
    1064             :     // TODO If there were multiple insertion points, this approximation can be
    1065             :     // wrong. We need to re-run the distribution algorithm. In the meantime,
    1066             :     // this should work well enough.
    1067          17 :     uint32_t index = aAppend ? point->InsertedChildrenLength() : 0;
    1068          17 :     for (nsIContent* currentSibling = aChild->GetPreviousSibling();
    1069          17 :          currentSibling;
    1070           0 :          currentSibling = currentSibling->GetPreviousSibling()) {
    1071             :       // If we find one of our previous siblings in the insertion point, the
    1072             :       // index following it is the correct insertion point. Otherwise, we guess
    1073             :       // based on whether we're appending or inserting.
    1074          13 :       int32_t pointIndex = point->IndexOfInsertedChild(currentSibling);
    1075          13 :       if (pointIndex != -1) {
    1076          13 :         index = pointIndex + 1;
    1077          13 :         break;
    1078             :       }
    1079             :     }
    1080             : 
    1081          17 :     point->InsertInsertedChildAt(aChild, index);
    1082             : 
    1083          17 :     nsIContent* newParent = point->GetParent();
    1084          17 :     if (newParent == parent) {
    1085           4 :       break;
    1086             :     }
    1087             : 
    1088          13 :     parent = newParent;
    1089             :   }
    1090             : }
    1091             : 
    1092             : 
    1093             : nsIContent*
    1094          46 : nsBindingManager::FindNestedInsertionPoint(nsIContent* aContainer,
    1095             :                                            nsIContent* aChild)
    1096             : {
    1097          46 :   NS_PRECONDITION(aChild->GetParent() == aContainer,
    1098             :                   "Wrong container");
    1099             : 
    1100          46 :   nsIContent* parent = aContainer;
    1101          46 :   if (aContainer->IsActiveChildrenElement()) {
    1102           0 :     if (static_cast<XBLChildrenElement*>(aContainer)->
    1103             :           HasInsertedChildren()) {
    1104           0 :       return nullptr;
    1105             :     }
    1106           0 :     parent = aContainer->GetParent();
    1107             :   }
    1108             : 
    1109         114 :   while (parent) {
    1110          80 :     nsXBLBinding* binding = GetBindingWithContent(parent);
    1111          80 :     if (!binding) {
    1112          39 :       break;
    1113             :     }
    1114             : 
    1115          41 :     XBLChildrenElement* point = binding->FindInsertionPointFor(aChild);
    1116          41 :     if (!point) {
    1117           0 :       return nullptr;
    1118             :     }
    1119             : 
    1120          41 :     nsIContent* newParent = point->GetParent();
    1121          41 :     if (newParent == parent) {
    1122           7 :       break;
    1123             :     }
    1124          34 :     parent = newParent;
    1125             :   }
    1126             : 
    1127          46 :   return parent;
    1128             : }
    1129             : 
    1130             : nsIContent*
    1131          41 : nsBindingManager::FindNestedSingleInsertionPoint(nsIContent* aContainer,
    1132             :                                                  bool* aMulti)
    1133             : {
    1134          41 :   *aMulti = false;
    1135             : 
    1136          41 :   nsIContent* parent = aContainer;
    1137          41 :   if (aContainer->IsActiveChildrenElement()) {
    1138           0 :     if (static_cast<XBLChildrenElement*>(aContainer)->
    1139             :           HasInsertedChildren()) {
    1140           0 :       return nullptr;
    1141             :     }
    1142           0 :     parent = aContainer->GetParent();
    1143             :   }
    1144             : 
    1145          41 :   while(parent) {
    1146          41 :     nsXBLBinding* binding = GetBindingWithContent(parent);
    1147          41 :     if (!binding) {
    1148          36 :       break;
    1149             :     }
    1150             : 
    1151           5 :     if (binding->HasFilteredInsertionPoints()) {
    1152           4 :       *aMulti = true;
    1153           4 :       return nullptr;
    1154             :     }
    1155             : 
    1156           1 :     XBLChildrenElement* point = binding->GetDefaultInsertionPoint();
    1157           1 :     if (!point) {
    1158           0 :       return nullptr;
    1159             :     }
    1160             : 
    1161           1 :     nsIContent* newParent = point->GetParent();
    1162           1 :     if (newParent == parent) {
    1163           1 :       break;
    1164             :     }
    1165           0 :     parent = newParent;
    1166             :   }
    1167             : 
    1168          37 :   return parent;
    1169             : }

Generated by: LCOV version 1.13