1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
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/. */
7 #include "ImportManager.h"
9 #include "mozilla/EventListenerManager.h"
10 #include "HTMLLinkElement.h"
11 #include "nsContentPolicyUtils.h"
12 #include "nsContentUtils.h"
13 #include "nsCORSListenerProxy.h"
14 #include "nsIChannel.h"
15 #include "nsIContentPolicy.h"
16 #include "nsIContentSecurityPolicy.h"
17 #include "nsIDocument.h"
18 #include "nsIDOMDocument.h"
19 #include "nsIDOMEvent.h"
20 #include "nsIPrincipal.h"
21 #include "nsIScriptObjectPrincipal.h"
22 #include "nsScriptLoader.h"
23 #include "nsNetUtil.h"
25 //-----------------------------------------------------------------------------
27 //-----------------------------------------------------------------------------
31 explicit AutoError(mozilla::dom::ImportLoader
* loader
, bool scriptsBlocked
= true)
34 , mScriptsBlocked(scriptsBlocked
)
40 mLoader
->Error(mScriptsBlocked
);
44 void Pass() { mPassed
= true; }
47 mozilla::dom::ImportLoader
* mLoader
;
55 //-----------------------------------------------------------------------------
56 // ImportLoader::Updater
57 //-----------------------------------------------------------------------------
60 ImportLoader::Updater::GetReferrerChain(nsINode
* aNode
,
61 nsTArray
<nsINode
*>& aResult
)
63 // We fill up the array backward. First the last link: aNode.
64 MOZ_ASSERT(mLoader
->mLinks
.Contains(aNode
));
66 aResult
.AppendElement(aNode
);
67 nsINode
* node
= aNode
;
68 nsRefPtr
<ImportManager
> manager
= mLoader
->Manager();
69 for (ImportLoader
* referrersLoader
= manager
->Find(node
->OwnerDoc());
71 referrersLoader
= manager
->Find(node
->OwnerDoc()))
73 // Then walking up the main referrer chain and append each link
75 node
= referrersLoader
->GetMainReferrer();
77 aResult
.AppendElement(node
);
80 // The reversed order is more useful for consumers.
81 // XXX: This should probably go to nsTArray or some generic utility
82 // lib for our containers that we don't have... I would really like to
83 // get rid of this part...
84 uint32_t l
= aResult
.Length();
85 for (uint32_t i
= 0; i
< l
/ 2; i
++) {
86 Swap(aResult
[i
], aResult
[l
- i
- 1]);
91 ImportLoader::Updater::ShouldUpdate(nsTArray
<nsINode
*>& aNewPath
)
93 if (mLoader
->Manager()->GetNearestPredecessor(mLoader
->GetMainReferrer()) !=
94 mLoader
->mBlockingPredecessor
) {
97 // Let's walk down on the main referrer chains of both the current main and
98 // the new link, and find the last pair of links that are from the same
99 // document. This is the junction point between the two referrer chain. Their
100 // order in the subimport list of that document will determine if we have to
101 // update the spanning tree or this new edge changes nothing in the script
103 nsTArray
<nsINode
*> oldPath
;
104 GetReferrerChain(mLoader
->mLinks
[mLoader
->mMainReferrer
], oldPath
);
105 uint32_t max
= std::min(oldPath
.Length(), aNewPath
.Length());
107 uint32_t lastCommonImportAncestor
= 0;
110 i
< max
&& oldPath
[i
]->OwnerDoc() == aNewPath
[i
]->OwnerDoc();
113 lastCommonImportAncestor
= i
;
116 MOZ_ASSERT(lastCommonImportAncestor
< max
);
117 nsINode
* oldLink
= oldPath
[lastCommonImportAncestor
];
118 nsINode
* newLink
= aNewPath
[lastCommonImportAncestor
];
120 if ((lastCommonImportAncestor
== max
- 1) &&
121 newLink
== oldLink
) {
122 // If one chain contains the other entirely, then this is a simple cycle,
123 // nothing to be done here.
124 MOZ_ASSERT(oldPath
.Length() != aNewPath
.Length(),
125 "This would mean that new link == main referrer link");
129 MOZ_ASSERT(aNewPath
!= oldPath
,
130 "How could this happen?");
131 nsIDocument
* doc
= oldLink
->OwnerDoc();
132 MOZ_ASSERT(doc
->HasSubImportLink(newLink
));
133 MOZ_ASSERT(doc
->HasSubImportLink(oldLink
));
135 return doc
->IndexOfSubImportLink(newLink
) < doc
->IndexOfSubImportLink(oldLink
);
139 ImportLoader::Updater::UpdateMainReferrer(uint32_t aNewIdx
)
141 MOZ_ASSERT(aNewIdx
< mLoader
->mLinks
.Length());
142 nsINode
* newMainReferrer
= mLoader
->mLinks
[aNewIdx
];
144 // This new link means we have to execute our scripts sooner...
145 // Let's make sure that unblocking a loader does not trigger a script execution.
146 // So we start with placing the new blockers and only then will we remove any
148 if (mLoader
->IsBlocking()) {
149 // Our import parent is changed, let's block the new one and later unblock
151 newMainReferrer
->OwnerDoc()->ScriptLoader()->AddExecuteBlocker();
152 newMainReferrer
->OwnerDoc()->BlockDOMContentLoaded();
155 if (mLoader
->mDocument
) {
156 // Our nearest predecessor has changed. So let's add the ScriptLoader to the
157 // new one if there is any. And remove it from the old one.
158 nsRefPtr
<ImportManager
> manager
= mLoader
->Manager();
159 nsScriptLoader
* loader
= mLoader
->mDocument
->ScriptLoader();
160 ImportLoader
*& pred
= mLoader
->mBlockingPredecessor
;
161 ImportLoader
* newPred
= manager
->GetNearestPredecessor(newMainReferrer
);
164 newPred
->AddBlockedScriptLoader(loader
);
166 pred
->RemoveBlockedScriptLoader(loader
);
170 if (mLoader
->IsBlocking()) {
171 mLoader
->mImportParent
->ScriptLoader()->RemoveExecuteBlocker();
172 mLoader
->mImportParent
->UnblockDOMContentLoaded();
175 // Finally update mMainReferrer to point to the newly added link.
176 mLoader
->mMainReferrer
= aNewIdx
;
177 mLoader
->mImportParent
= newMainReferrer
->OwnerDoc();
181 ImportLoader::Updater::NextDependant(nsINode
* aCurrentLink
,
182 nsTArray
<nsINode
*>& aPath
,
183 NodeTable
& aVisitedNodes
, bool aSkipChildren
)
185 // Depth first graph traversal.
186 if (!aSkipChildren
) {
188 ImportLoader
* loader
= mLoader
->Manager()->Find(aCurrentLink
);
189 if (loader
&& loader
->GetDocument()) {
190 nsINode
* firstSubImport
= loader
->GetDocument()->GetSubImportLink(0);
191 if (firstSubImport
&& !aVisitedNodes
.Contains(firstSubImport
)) {
192 aPath
.AppendElement(aCurrentLink
);
193 aVisitedNodes
.PutEntry(firstSubImport
);
194 return firstSubImport
;
199 aPath
.AppendElement(aCurrentLink
);
200 // "(parent's) next sibling"
201 while(aPath
.Length() > 1) {
202 aCurrentLink
= aPath
[aPath
.Length() - 1];
203 aPath
.RemoveElementAt(aPath
.Length() - 1);
205 // Let's find the next "sibling"
206 ImportLoader
* loader
= mLoader
->Manager()->Find(aCurrentLink
->OwnerDoc());
207 MOZ_ASSERT(loader
&& loader
->GetDocument(), "How can this happend?");
208 nsIDocument
* doc
= loader
->GetDocument();
209 MOZ_ASSERT(doc
->HasSubImportLink(aCurrentLink
));
210 uint32_t idx
= doc
->IndexOfSubImportLink(aCurrentLink
);
211 nsINode
* next
= doc
->GetSubImportLink(idx
+ 1);
213 // Note: If we found an already visited link that means the parent links has
214 // closed the circle it's always the "first child" section that should find
215 // the first already visited node. Let's just assert that.
216 MOZ_ASSERT(!aVisitedNodes
.Contains(next
));
217 aVisitedNodes
.PutEntry(next
);
226 ImportLoader::Updater::UpdateDependants(nsINode
* aNode
,
227 nsTArray
<nsINode
*>& aPath
)
229 NodeTable visitedNodes
;
230 nsINode
* current
= aNode
;
231 uint32_t initialLength
= aPath
.Length();
232 bool neededUpdate
= true;
233 while ((current
= NextDependant(current
, aPath
, visitedNodes
, !neededUpdate
))) {
234 if (!current
|| aPath
.Length() <= initialLength
) {
237 ImportLoader
* loader
= mLoader
->Manager()->Find(current
);
241 Updater
& updater
= loader
->mUpdater
;
242 neededUpdate
= updater
.ShouldUpdate(aPath
);
244 updater
.UpdateMainReferrer(loader
->mLinks
.IndexOf(current
));
250 ImportLoader::Updater::UpdateSpanningTree(nsINode
* aNode
)
252 if (mLoader
->mReady
|| mLoader
->mStopped
) {
253 // Scripts already executed, nothing to be done here.
257 if (mLoader
->mLinks
.Length() == 1) {
258 // If this is the first referrer, let's mark it.
259 mLoader
->mMainReferrer
= 0;
263 nsTArray
<nsINode
*> newReferrerChain
;
264 GetReferrerChain(aNode
, newReferrerChain
);
265 if (ShouldUpdate(newReferrerChain
)) {
266 UpdateMainReferrer(mLoader
->mLinks
.Length() - 1);
267 UpdateDependants(aNode
, newReferrerChain
);
271 //-----------------------------------------------------------------------------
273 //-----------------------------------------------------------------------------
275 NS_INTERFACE_MAP_BEGIN(ImportLoader
)
276 NS_INTERFACE_MAP_ENTRY(nsIStreamListener
)
277 NS_INTERFACE_MAP_ENTRY(nsIRequestObserver
)
278 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(ImportLoader
)
281 NS_IMPL_CYCLE_COLLECTING_ADDREF(ImportLoader
)
282 NS_IMPL_CYCLE_COLLECTING_RELEASE(ImportLoader
)
284 NS_IMPL_CYCLE_COLLECTION(ImportLoader
,
289 ImportLoader::ImportLoader(nsIURI
* aURI
, nsIDocument
* aImportParent
)
291 , mImportParent(aImportParent
)
292 , mBlockingPredecessor(nullptr)
295 , mBlockingScripts(false)
301 ImportLoader::BlockScripts()
303 MOZ_ASSERT(!mBlockingScripts
);
304 mImportParent
->ScriptLoader()->AddExecuteBlocker();
305 mImportParent
->BlockDOMContentLoaded();
306 mBlockingScripts
= true;
310 ImportLoader::UnblockScripts()
312 MOZ_ASSERT(mBlockingScripts
);
313 mImportParent
->ScriptLoader()->RemoveExecuteBlocker();
314 mImportParent
->UnblockDOMContentLoaded();
315 for (uint32_t i
= 0; i
< mBlockedScriptLoaders
.Length(); i
++) {
316 mBlockedScriptLoaders
[i
]->RemoveExecuteBlocker();
318 mBlockedScriptLoaders
.Clear();
319 mBlockingScripts
= false;
323 ImportLoader::SetBlockingPredecessor(ImportLoader
* aLoader
)
325 mBlockingPredecessor
= aLoader
;
329 ImportLoader::DispatchEventIfFinished(nsINode
* aNode
)
331 MOZ_ASSERT(!(mReady
&& mStopped
));
333 DispatchLoadEvent(aNode
);
336 DispatchErrorEvent(aNode
);
341 ImportLoader::AddBlockedScriptLoader(nsScriptLoader
* aScriptLoader
)
343 if (mBlockedScriptLoaders
.Contains(aScriptLoader
)) {
347 aScriptLoader
->AddExecuteBlocker();
349 // Let's keep track of the pending script loaders.
350 mBlockedScriptLoaders
.AppendElement(aScriptLoader
);
354 ImportLoader::RemoveBlockedScriptLoader(nsScriptLoader
* aScriptLoader
)
356 aScriptLoader
->RemoveExecuteBlocker();
357 return mBlockedScriptLoaders
.RemoveElement(aScriptLoader
);
361 ImportLoader::AddLinkElement(nsINode
* aNode
)
363 // If a new link element is added to the import tree that
364 // refers to an import that is already finished loading or
365 // stopped trying, we need to fire the corresponding event
367 mLinks
.AppendElement(aNode
);
368 mUpdater
.UpdateSpanningTree(aNode
);
369 DispatchEventIfFinished(aNode
);
373 ImportLoader::RemoveLinkElement(nsINode
* aNode
)
375 mLinks
.RemoveElement(aNode
);
378 // Events has to be fired with a script runner, so mImport can
379 // be set on the link element before the load event is fired even
380 // if ImportLoader::Get returns an already loaded import and we
381 // fire the load event immediately on the new referring link element.
382 class AsyncEvent
: public nsRunnable
{
384 AsyncEvent(nsINode
* aNode
, bool aSuccess
)
392 return nsContentUtils::DispatchTrustedEvent(mNode
->OwnerDoc(),
394 mSuccess
? NS_LITERAL_STRING("load")
395 : NS_LITERAL_STRING("error"),
396 /* aCanBubble = */ false,
397 /* aCancelable = */ false);
401 nsCOMPtr
<nsINode
> mNode
;
406 ImportLoader::DispatchErrorEvent(nsINode
* aNode
)
408 nsContentUtils::AddScriptRunner(new AsyncEvent(aNode
, /* aSuccess = */ false));
412 ImportLoader::DispatchLoadEvent(nsINode
* aNode
)
414 nsContentUtils::AddScriptRunner(new AsyncEvent(aNode
, /* aSuccess = */ true));
421 uint32_t l
= mLinks
.Length();
422 for (uint32_t i
= 0; i
< l
; i
++) {
423 DispatchLoadEvent(mLinks
[i
]);
430 ImportLoader::Error(bool aUnblockScripts
)
434 uint32_t l
= mLinks
.Length();
435 for (uint32_t i
= 0; i
< l
; i
++) {
436 DispatchErrorEvent(mLinks
[i
]);
438 if (aUnblockScripts
) {
444 // Release all the resources we don't need after there is no more
445 // data available on the channel, and the parser is done.
446 void ImportLoader::ReleaseResources()
448 mParserStreamListener
= nullptr;
449 mImportParent
= nullptr;
453 ImportLoader::Principal()
455 MOZ_ASSERT(mImportParent
);
456 nsCOMPtr
<nsIDocument
> master
= mImportParent
->MasterDocument();
457 nsCOMPtr
<nsIScriptObjectPrincipal
> sop
= do_QueryInterface(master
);
459 return sop
->GetPrincipal();
465 AutoError
ae(this, false);
466 // Imports should obey to the master documents CSP.
467 nsCOMPtr
<nsIDocument
> master
= mImportParent
->MasterDocument();
468 nsIPrincipal
* principal
= Principal();
470 int16_t shouldLoad
= nsIContentPolicy::ACCEPT
;
471 nsresult rv
= NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SUBDOCUMENT
,
475 NS_LITERAL_CSTRING("text/html"),
476 /* extra = */ nullptr,
478 nsContentUtils::GetContentPolicy(),
479 nsContentUtils::GetSecurityManager());
480 if (NS_FAILED(rv
) || NS_CP_REJECTED(shouldLoad
)) {
481 NS_WARN_IF_FALSE(NS_CP_ACCEPTED(shouldLoad
), "ImportLoader rejected by CSP");
485 nsIScriptSecurityManager
* secMan
= nsContentUtils::GetSecurityManager();
486 rv
= secMan
->CheckLoadURIWithPrincipal(principal
, mURI
,
487 nsIScriptSecurityManager::STANDARD
);
488 NS_ENSURE_SUCCESS_VOID(rv
);
490 nsCOMPtr
<nsILoadGroup
> loadGroup
= master
->GetDocumentLoadGroup();
491 nsCOMPtr
<nsIChannel
> channel
;
492 rv
= NS_NewChannel(getter_AddRefs(channel
),
495 nsILoadInfo::SEC_NORMAL
,
496 nsIContentPolicy::TYPE_SUBDOCUMENT
,
498 nullptr, // aCallbacks
499 nsIRequest::LOAD_BACKGROUND
);
501 NS_ENSURE_SUCCESS_VOID(rv
);
503 // Init CORSListenerProxy and omit credentials.
504 nsRefPtr
<nsCORSListenerProxy
> corsListener
=
505 new nsCORSListenerProxy(this, principal
,
506 /* aWithCredentials */ false);
507 rv
= corsListener
->Init(channel
, true);
508 NS_ENSURE_SUCCESS_VOID(rv
);
510 rv
= channel
->AsyncOpen(corsListener
, nullptr);
511 NS_ENSURE_SUCCESS_VOID(rv
);
518 ImportLoader::OnDataAvailable(nsIRequest
* aRequest
,
519 nsISupports
* aContext
,
520 nsIInputStream
* aStream
,
524 MOZ_ASSERT(mParserStreamListener
);
528 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(aRequest
, &rv
);
529 NS_ENSURE_SUCCESS(rv
, rv
);
531 rv
= mParserStreamListener
->OnDataAvailable(channel
, aContext
,
534 NS_ENSURE_SUCCESS(rv
, rv
);
540 ImportLoader::HandleEvent(nsIDOMEvent
*aEvent
)
544 aEvent
->GetType(type
);
545 MOZ_ASSERT(type
.EqualsLiteral("DOMContentLoaded"));
552 ImportLoader::OnStopRequest(nsIRequest
* aRequest
,
553 nsISupports
* aContext
,
556 // OnStartRequest throws a special error code to let us know that we
557 // shouldn't do anything else.
558 if (aStatus
== NS_ERROR_DOM_ABORT_ERR
) {
559 // We failed in OnStartRequest, nothing more to do (we've already
560 // dispatched an error event) just return here.
561 MOZ_ASSERT(mStopped
);
565 if (mParserStreamListener
) {
566 mParserStreamListener
->OnStopRequest(aRequest
, aContext
, aStatus
);
570 // If at this point we don't have a document, then the error was
572 return NS_ERROR_DOM_ABORT_ERR
;
575 nsCOMPtr
<EventTarget
> eventTarget
= do_QueryInterface(mDocument
);
576 EventListenerManager
* manager
= eventTarget
->GetOrCreateListenerManager();
577 manager
->AddEventListenerByType(this,
578 NS_LITERAL_STRING("DOMContentLoaded"),
579 TrustedEventsAtSystemGroupBubble());
584 ImportLoader::OnStartRequest(nsIRequest
* aRequest
, nsISupports
* aContext
)
587 nsIPrincipal
* principal
= Principal();
589 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(aRequest
);
591 return NS_ERROR_DOM_ABORT_ERR
;
594 if (nsContentUtils::IsSystemPrincipal(principal
)) {
595 // We should never import non-system documents and run their scripts with system principal!
596 nsCOMPtr
<nsIPrincipal
> channelPrincipal
;
597 nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(channel
,
598 getter_AddRefs(channelPrincipal
));
599 if (!nsContentUtils::IsSystemPrincipal(channelPrincipal
)) {
600 return NS_ERROR_FAILURE
;
603 channel
->SetOwner(principal
);
606 channel
->GetContentType(type
);
607 if (!type
.EqualsLiteral("text/html")) {
608 NS_WARNING("ImportLoader wrong content type");
609 return NS_ERROR_DOM_ABORT_ERR
;
612 // The scope object is same for all the imports in an import tree,
613 // let's get it form the import parent.
614 nsCOMPtr
<nsIGlobalObject
> global
= mImportParent
->GetScopeObject();
615 nsCOMPtr
<nsIDOMDocument
> importDoc
;
616 nsCOMPtr
<nsIURI
> baseURI
= mImportParent
->GetBaseURI();
617 const nsAString
& emptyStr
= EmptyString();
618 nsresult rv
= NS_NewDOMDocument(getter_AddRefs(importDoc
),
619 emptyStr
, emptyStr
, nullptr, mURI
,
620 baseURI
, principal
, false, global
,
622 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_ABORT_ERR
);
624 // The imported document must know which master document it belongs to.
625 mDocument
= do_QueryInterface(importDoc
);
626 nsCOMPtr
<nsIDocument
> master
= mImportParent
->MasterDocument();
627 mDocument
->SetMasterDocument(master
);
629 // We want to inherit the sandbox flags from the master document.
630 mDocument
->SetSandboxFlags(master
->GetSandboxFlags());
632 // We have to connect the blank document we created with the channel we opened,
633 // and create its own LoadGroup for it.
634 nsCOMPtr
<nsIStreamListener
> listener
;
635 nsCOMPtr
<nsILoadGroup
> loadGroup
;
636 channel
->GetLoadGroup(getter_AddRefs(loadGroup
));
637 nsCOMPtr
<nsILoadGroup
> newLoadGroup
= do_CreateInstance(NS_LOADGROUP_CONTRACTID
);
638 NS_ENSURE_TRUE(newLoadGroup
, NS_ERROR_OUT_OF_MEMORY
);
639 newLoadGroup
->SetLoadGroup(loadGroup
);
640 rv
= mDocument
->StartDocumentLoad("import", channel
, newLoadGroup
,
641 nullptr, getter_AddRefs(listener
),
643 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_ABORT_ERR
);
645 nsCOMPtr
<nsIURI
> originalURI
;
646 rv
= channel
->GetOriginalURI(getter_AddRefs(originalURI
));
647 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_ABORT_ERR
);
649 nsCOMPtr
<nsIURI
> URI
;
650 rv
= channel
->GetURI(getter_AddRefs(URI
));
651 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_ABORT_ERR
);
652 MOZ_ASSERT(URI
, "URI of a channel should never be null");
655 rv
= URI
->Equals(originalURI
, &equals
);
656 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_ABORT_ERR
);
659 // In case of a redirection we must add the new URI to the import map.
660 Manager()->AddLoaderWithNewURI(this, URI
);
663 // Let's start the parser.
664 mParserStreamListener
= listener
;
665 rv
= listener
->OnStartRequest(aRequest
, aContext
);
666 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_ABORT_ERR
);
672 //-----------------------------------------------------------------------------
674 //-----------------------------------------------------------------------------
676 NS_IMPL_CYCLE_COLLECTION(ImportManager
,
679 NS_INTERFACE_MAP_BEGIN(ImportManager
)
680 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(ImportManager
)
683 NS_IMPL_CYCLE_COLLECTING_ADDREF(ImportManager
)
684 NS_IMPL_CYCLE_COLLECTING_RELEASE(ImportManager
)
686 already_AddRefed
<ImportLoader
>
687 ImportManager::Get(nsIURI
* aURI
, nsINode
* aNode
, nsIDocument
* aOrigDocument
)
689 // Check if we have a loader for that URI, if not create one,
691 nsRefPtr
<ImportLoader
> loader
;
692 mImports
.Get(aURI
, getter_AddRefs(loader
));
693 bool needToStart
= false;
695 loader
= new ImportLoader(aURI
, aOrigDocument
);
696 mImports
.Put(aURI
, loader
);
701 // Let's keep track of the sub imports links in each document. It will
702 // be used later for scrip execution order calculation. (see UpdateSpanningTree)
703 // NOTE: removing and adding back the link to the tree somewhere else will
704 // NOT have an effect on script execution order.
705 if (!aOrigDocument
->HasSubImportLink(aNode
)) {
706 aOrigDocument
->AddSubImportLink(aNode
);
709 loader
->AddLinkElement(aNode
);
715 return loader
.forget();
719 ImportManager::Find(nsIDocument
* aImport
)
721 return mImports
.GetWeak(aImport
->GetDocumentURIObject());
725 ImportManager::Find(nsINode
* aLink
)
727 HTMLLinkElement
* linkElement
= static_cast<HTMLLinkElement
*>(aLink
);
728 nsCOMPtr
<nsIURI
> uri
= linkElement
->GetHrefURI();
729 return mImports
.GetWeak(uri
);
733 ImportManager::AddLoaderWithNewURI(ImportLoader
* aLoader
, nsIURI
* aNewURI
)
735 mImports
.Put(aNewURI
, aLoader
);
738 nsRefPtr
<ImportLoader
> ImportManager::GetNearestPredecessor(nsINode
* aNode
)
740 // Return the previous link if there is any in the same document.
741 nsIDocument
* doc
= aNode
->OwnerDoc();
742 int32_t idx
= doc
->IndexOfSubImportLink(aNode
);
743 MOZ_ASSERT(idx
!= -1, "aNode must be a sub import link of its owner document");
745 for (; idx
> 0; idx
--) {
746 HTMLLinkElement
* link
=
747 static_cast<HTMLLinkElement
*>(doc
->GetSubImportLink(idx
- 1));
748 nsCOMPtr
<nsIURI
> uri
= link
->GetHrefURI();
749 nsRefPtr
<ImportLoader
> ret
;
750 mImports
.Get(uri
, getter_AddRefs(ret
));
751 // Only main referrer links are interesting.
752 if (ret
->GetMainReferrer() == link
) {
758 if (doc
->IsMasterDocument()) {
759 // If there is no previous one, and it was the master document, then
760 // there is no predecessor.
763 // Else we find the main referrer of the import parent of the link's document.
764 // And do a recursion.
765 ImportLoader
* owner
= Find(doc
);
767 nsCOMPtr
<nsINode
> mainReferrer
= owner
->GetMainReferrer();
768 return GetNearestPredecessor(mainReferrer
);
775 } // namespace mozilla