mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 877072 - HTML Imports part1. r=mrbkap
This commit is contained in:
parent
0935bd8594
commit
66c718a038
@ -106,6 +106,7 @@ struct ElementRegistrationOptions;
|
||||
class Event;
|
||||
class EventTarget;
|
||||
class FrameRequestCallback;
|
||||
class ImportManager;
|
||||
class OverfillCallback;
|
||||
class HTMLBodyElement;
|
||||
struct LifecycleCallbackArgs;
|
||||
@ -129,8 +130,8 @@ typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0x906d05e7, 0x39af, 0x4ff0, \
|
||||
{ 0xbc, 0xcd, 0x30, 0x0c, 0x7f, 0xeb, 0x86, 0x21 } }
|
||||
{ 0x0300e2e0, 0x24c9, 0x4ecf, \
|
||||
{ 0x81, 0xec, 0x64, 0x26, 0x9a, 0x4b, 0xef, 0x18 } }
|
||||
|
||||
// Flag for AddStyleSheet().
|
||||
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
||||
@ -2255,6 +2256,13 @@ public:
|
||||
|
||||
virtual JSObject* WrapObject(JSContext *aCx) MOZ_OVERRIDE;
|
||||
|
||||
// Each import tree has exactly one master document which is
|
||||
// the root of the tree, and owns the browser context.
|
||||
virtual already_AddRefed<nsIDocument> MasterDocument() = 0;
|
||||
virtual void SetMasterDocument(nsIDocument* master) = 0;
|
||||
virtual bool IsMasterDocument() = 0;
|
||||
virtual already_AddRefed<mozilla::dom::ImportManager> ImportManager() = 0;
|
||||
|
||||
private:
|
||||
uint64_t mWarnedAbout;
|
||||
SelectorCache mSelectorCache;
|
||||
|
@ -17,8 +17,8 @@
|
||||
#include "mozilla/CORSMode.h"
|
||||
|
||||
#define NS_ISCRIPTELEMENT_IID \
|
||||
{ 0x491628bc, 0xce7c, 0x4db4, \
|
||||
{ 0x93, 0x3f, 0xce, 0x1b, 0x75, 0xee, 0x75, 0xce } }
|
||||
{ 0xe60fca9b, 0x1b96, 0x4e4e, \
|
||||
{ 0xa9, 0xb4, 0xdc, 0x98, 0x4f, 0x88, 0x3f, 0x9c } }
|
||||
|
||||
/**
|
||||
* Internal interface implemented by script elements
|
||||
|
368
content/base/src/ImportManager.cpp
Normal file
368
content/base/src/ImportManager.cpp
Normal file
@ -0,0 +1,368 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ImportManager.h"
|
||||
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
#include "HTMLLinkElement.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIChannelPolicy.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsScriptLoader.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
class AutoError {
|
||||
public:
|
||||
AutoError(mozilla::dom::ImportLoader* loader)
|
||||
: mLoader(loader)
|
||||
, mPassed(false)
|
||||
{}
|
||||
|
||||
~AutoError()
|
||||
{
|
||||
if (!mPassed) {
|
||||
mLoader->Error();
|
||||
}
|
||||
}
|
||||
|
||||
void Pass() { mPassed = true; }
|
||||
|
||||
private:
|
||||
mozilla::dom::ImportLoader* mLoader;
|
||||
bool mPassed;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(ImportLoader)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
|
||||
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(ImportLoader)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ImportLoader)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ImportLoader)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(ImportLoader,
|
||||
mDocument,
|
||||
mLinks)
|
||||
|
||||
ImportLoader::ImportLoader(nsIURI* aURI, nsIDocument* aImportParent)
|
||||
: mURI(aURI)
|
||||
, mImportParent(aImportParent)
|
||||
, mReady(false)
|
||||
, mStopped(false)
|
||||
, mBlockingScripts(false)
|
||||
{}
|
||||
|
||||
void
|
||||
ImportLoader::BlockScripts()
|
||||
{
|
||||
MOZ_ASSERT(!mBlockingScripts);
|
||||
mImportParent->ScriptLoader()->AddExecuteBlocker();
|
||||
mBlockingScripts = true;
|
||||
}
|
||||
|
||||
void
|
||||
ImportLoader::UnblockScripts()
|
||||
{
|
||||
MOZ_ASSERT(mBlockingScripts);
|
||||
mImportParent->ScriptLoader()->RemoveExecuteBlocker();
|
||||
mBlockingScripts = false;
|
||||
}
|
||||
|
||||
void
|
||||
ImportLoader::DispatchEventIfFinished(nsINode* aNode)
|
||||
{
|
||||
MOZ_ASSERT(!(mReady && mStopped));
|
||||
if (mReady) {
|
||||
DispatchLoadEvent(aNode);
|
||||
}
|
||||
if (mStopped) {
|
||||
DispatchErrorEvent(aNode);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImportLoader::AddLinkElement(nsINode* aNode)
|
||||
{
|
||||
// If a new link element is added to the import tree that
|
||||
// refers to an import that is already finished loading or
|
||||
// stopped trying, we need to fire the corresponding event
|
||||
// on it.
|
||||
mLinks.AppendObject(aNode);
|
||||
DispatchEventIfFinished(aNode);
|
||||
}
|
||||
|
||||
void
|
||||
ImportLoader::RemoveLinkElement(nsINode* aNode)
|
||||
{
|
||||
mLinks.RemoveObject(aNode);
|
||||
}
|
||||
|
||||
// Events has to be fired with a script runner, so mImport can
|
||||
// be set on the link element before the load event is fired even
|
||||
// if ImportLoader::Get returns an already loaded import and we
|
||||
// fire the load event immediately on the new referring link element.
|
||||
class AsyncEvent : public nsRunnable {
|
||||
public:
|
||||
AsyncEvent(nsINode* aNode, bool aSuccess)
|
||||
: mNode(aNode)
|
||||
, mSuccess(aSuccess)
|
||||
{
|
||||
MOZ_ASSERT(mNode);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
return nsContentUtils::DispatchTrustedEvent(mNode->OwnerDoc(),
|
||||
mNode,
|
||||
mSuccess ? NS_LITERAL_STRING("load")
|
||||
: NS_LITERAL_STRING("error"),
|
||||
/* aCanBubble = */ true,
|
||||
/* aCancelable = */ true);
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsINode> mNode;
|
||||
bool mSuccess;
|
||||
};
|
||||
|
||||
void
|
||||
ImportLoader::DispatchErrorEvent(nsINode* aNode)
|
||||
{
|
||||
nsContentUtils::AddScriptRunner(new AsyncEvent(aNode, /* aSuccess = */ false));
|
||||
}
|
||||
|
||||
void
|
||||
ImportLoader::DispatchLoadEvent(nsINode* aNode)
|
||||
{
|
||||
nsContentUtils::AddScriptRunner(new AsyncEvent(aNode, /* aSuccess = */ true));
|
||||
}
|
||||
|
||||
void
|
||||
ImportLoader::Done()
|
||||
{
|
||||
mReady = true;
|
||||
uint32_t count = mLinks.Count();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
DispatchLoadEvent(mLinks[i]);
|
||||
}
|
||||
UnblockScripts();
|
||||
ReleaseResources();
|
||||
}
|
||||
|
||||
void
|
||||
ImportLoader::Error()
|
||||
{
|
||||
mDocument = nullptr;
|
||||
mStopped = true;
|
||||
uint32_t count = mLinks.Count();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
DispatchErrorEvent(mLinks[i]);
|
||||
}
|
||||
UnblockScripts();
|
||||
ReleaseResources();
|
||||
}
|
||||
|
||||
// Release all the resources we don't need after there is no more
|
||||
// data available on the channel, and the parser is done.
|
||||
void ImportLoader::ReleaseResources()
|
||||
{
|
||||
mParserStreamListener = nullptr;
|
||||
mChannel = nullptr;
|
||||
mImportParent = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ImportLoader::Open()
|
||||
{
|
||||
AutoError ae(this);
|
||||
// Imports should obey to the master documents CSP.
|
||||
nsCOMPtr<nsIDocument> master = mImportParent->MasterDocument();
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(master);
|
||||
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
|
||||
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
|
||||
nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT,
|
||||
mURI,
|
||||
principal,
|
||||
mImportParent,
|
||||
NS_LITERAL_CSTRING("text/html"),
|
||||
/* extra = */ nullptr,
|
||||
&shouldLoad,
|
||||
nsContentUtils::GetContentPolicy(),
|
||||
nsContentUtils::GetSecurityManager());
|
||||
if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
|
||||
NS_WARN_IF_FALSE(NS_CP_ACCEPTED(shouldLoad), "ImportLoader rejected by CSP");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = mImportParent->GetDocumentLoadGroup();
|
||||
nsCOMPtr<nsIChannelPolicy> channelPolicy;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = principal->GetCsp(getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
if (csp) {
|
||||
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
|
||||
channelPolicy->SetContentSecurityPolicy(csp);
|
||||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
|
||||
}
|
||||
rv = NS_NewChannel(getter_AddRefs(mChannel),
|
||||
mURI,
|
||||
/* ioService = */ nullptr,
|
||||
loadGroup,
|
||||
/* callbacks = */ nullptr,
|
||||
nsIRequest::LOAD_BACKGROUND,
|
||||
channelPolicy);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
mChannel->AsyncOpen(this, nullptr);
|
||||
BlockScripts();
|
||||
ae.Pass();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImportLoader::OnDataAvailable(nsIRequest* aRequest,
|
||||
nsISupports* aContext,
|
||||
nsIInputStream* aStream,
|
||||
uint64_t aOffset,
|
||||
uint32_t aCount)
|
||||
{
|
||||
MOZ_ASSERT(mParserStreamListener);
|
||||
|
||||
AutoError ae(this);
|
||||
nsresult rv = mParserStreamListener->OnDataAvailable(mChannel, aContext,
|
||||
aStream, aOffset,
|
||||
aCount);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
ae.Pass();
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImportLoader::HandleEvent(nsIDOMEvent *aEvent)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
nsAutoString type;
|
||||
aEvent->GetType(type);
|
||||
MOZ_ASSERT(type.EqualsLiteral("DOMContentLoaded"));
|
||||
#endif
|
||||
Done();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImportLoader::OnStopRequest(nsIRequest* aRequest,
|
||||
nsISupports* aContext,
|
||||
nsresult aStatus)
|
||||
{
|
||||
MOZ_ASSERT(aRequest == mChannel,
|
||||
"Wrong channel something went horribly wrong");
|
||||
|
||||
if (mParserStreamListener) {
|
||||
mParserStreamListener->OnStopRequest(aRequest, aContext, aStatus);
|
||||
}
|
||||
|
||||
nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(mDocument);
|
||||
EventListenerManager* manager = eventTarget->GetOrCreateListenerManager();
|
||||
manager->AddEventListenerByType(this,
|
||||
NS_LITERAL_STRING("DOMContentLoaded"),
|
||||
TrustedEventsAtSystemGroupBubble());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImportLoader::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
|
||||
{
|
||||
MOZ_ASSERT(aRequest == mChannel,
|
||||
"Wrong channel, something went horribly wrong");
|
||||
|
||||
AutoError ae(this);
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mImportParent);
|
||||
nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
|
||||
mChannel->SetOwner(principal);
|
||||
|
||||
nsAutoCString type;
|
||||
mChannel->GetContentType(type);
|
||||
if (!type.EqualsLiteral("text/html")) {
|
||||
NS_WARNING("ImportLoader wrong content type");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// The scope object is same for all the imports in an import tree,
|
||||
// let's get it form the import parent.
|
||||
nsCOMPtr<nsIGlobalObject> global = mImportParent->GetScopeObject();
|
||||
nsCOMPtr<nsIDOMDocument> importDoc;
|
||||
nsCOMPtr<nsIURI> baseURI = mImportParent->GetBaseURI();
|
||||
const nsAString& emptyStr = EmptyString();
|
||||
nsresult rv = NS_NewDOMDocument(getter_AddRefs(importDoc),
|
||||
emptyStr, emptyStr, nullptr, mURI,
|
||||
baseURI, principal, false, global,
|
||||
DocumentFlavorHTML);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The imported document must know which master document it belongs to.
|
||||
mDocument = do_QueryInterface(importDoc);
|
||||
nsCOMPtr<nsIDocument> master = mImportParent->MasterDocument();
|
||||
mDocument->SetMasterDocument(master);
|
||||
|
||||
// We have to connect the blank document we created with the channel we opened.
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
mChannel->GetLoadGroup(getter_AddRefs(loadGroup));
|
||||
rv = mDocument->StartDocumentLoad("import", mChannel, loadGroup,
|
||||
nullptr, getter_AddRefs(listener),
|
||||
true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Let's start parser.
|
||||
mParserStreamListener = listener;
|
||||
rv = listener->OnStartRequest(aRequest, aContext);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ae.Pass();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(ImportManager,
|
||||
mImports)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(ImportManager)
|
||||
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(ImportManager)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ImportManager)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ImportManager)
|
||||
|
||||
already_AddRefed<ImportLoader>
|
||||
ImportManager::Get(nsIURI* aURI, nsINode* aNode, nsIDocument* aOrigDocument)
|
||||
{
|
||||
// Check if we have a loader for that URI, if not create one,
|
||||
// and start it up.
|
||||
nsRefPtr<ImportLoader> loader;
|
||||
mImports.Get(aURI, getter_AddRefs(loader));
|
||||
|
||||
if (!loader) {
|
||||
loader = new ImportLoader(aURI, aOrigDocument);
|
||||
mImports.Put(aURI, loader);
|
||||
loader->Open();
|
||||
}
|
||||
loader->AddLinkElement(aNode);
|
||||
MOZ_ASSERT(loader);
|
||||
return loader.forget();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
148
content/base/src/ImportManager.h
Normal file
148
content/base/src/ImportManager.h
Normal file
@ -0,0 +1,148 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
*
|
||||
* For each import tree there is one master document (the root) and one
|
||||
* import manager. The import manager is a map of URI ImportLoader pairs.
|
||||
* An ImportLoader is responsible for loading an import document from a
|
||||
* given location, and sending out load or error events to all the link
|
||||
* nodes that refer to it when it's done. For loading it opens up a
|
||||
* channel, using the same CSP as the master document. It then creates a
|
||||
* blank document, and starts parsing the data from the channel. When
|
||||
* there is no more data on the channel we wait for the DOMContentLoaded
|
||||
* event from the parsed document. For the duration of the loading
|
||||
* process the scripts on the parent documents are blocked. When an error
|
||||
* occurs, or the DOMContentLoaded event is received, the scripts on the
|
||||
* parent document are unblocked and we emit the corresponding event on
|
||||
* all the referrer link nodes. If a new link node is added to one of the
|
||||
* DOM trees in the import tree that refers to an import that was already
|
||||
* loaded, the already existing ImportLoader is being used (without
|
||||
* loading the referred import document twice) and if necessary the
|
||||
* load/error is emitted on it immediately.
|
||||
*
|
||||
* Ownership model:
|
||||
*
|
||||
* ImportDocument ----------------------------
|
||||
* ^ |
|
||||
* | v
|
||||
* MasterDocument <- ImportManager <-ImportLoader
|
||||
* ^ ^
|
||||
* | |
|
||||
* LinkElement <-----------------------------
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef mozilla_dom_ImportManager_h__
|
||||
#define mozilla_dom_ImportManager_h__
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsURIHashKey.h"
|
||||
|
||||
class nsIDocument;
|
||||
class nsIChannel;
|
||||
class nsINode;
|
||||
class AutoError;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ImportManager;
|
||||
|
||||
class ImportLoader MOZ_FINAL : public nsIStreamListener
|
||||
, public nsIDOMEventListener
|
||||
{
|
||||
friend class ::AutoError;
|
||||
friend class ImportManager;
|
||||
|
||||
public:
|
||||
ImportLoader(nsIURI* aURI, nsIDocument* aOriginDocument);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ImportLoader, nsIStreamListener)
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
||||
// We need to listen to DOMContentLoaded event to know when the document
|
||||
// is fully leaded.
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent) MOZ_OVERRIDE;
|
||||
|
||||
// Validation then opening and starting up the channel.
|
||||
void Open();
|
||||
void AddLinkElement(nsINode* aNode);
|
||||
void RemoveLinkElement(nsINode* aNode);
|
||||
bool IsReady() { return mReady; }
|
||||
bool IsStopped() { return mStopped; }
|
||||
bool IsBlocking() { return mBlockingScripts; }
|
||||
already_AddRefed<nsIDocument> GetImport()
|
||||
{
|
||||
return mReady ? nsCOMPtr<nsIDocument>(mDocument).forget() : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
// If a new referrer LinkElement was added, let's
|
||||
// see if we are already finished and if so fire
|
||||
// the right event.
|
||||
void DispatchEventIfFinished(nsINode* aNode);
|
||||
|
||||
// Dispatch event for a single referrer LinkElement.
|
||||
void DispatchErrorEvent(nsINode* aNode);
|
||||
void DispatchLoadEvent(nsINode* aNode);
|
||||
|
||||
// Must be called when an error has occured during load.
|
||||
void Error();
|
||||
|
||||
// Must be called when the import document has been loaded successfully.
|
||||
void Done();
|
||||
|
||||
// When the reading from the channel and the parsing
|
||||
// of the document is done, we can release the resources
|
||||
// that we don't need any longer to hold on.
|
||||
void ReleaseResources();
|
||||
|
||||
// While the document is being loaded we must block scripts
|
||||
// on the import parent document.
|
||||
void BlockScripts();
|
||||
void UnblockScripts();
|
||||
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsIStreamListener> mParserStreamListener;
|
||||
nsCOMPtr<nsIDocument> mImportParent;
|
||||
// List of the LinkElements that are referring to this import
|
||||
// we need to keep track of them so we can fire event on them.
|
||||
nsCOMArray<nsINode> mLinks;
|
||||
bool mReady;
|
||||
bool mStopped;
|
||||
bool mBlockingScripts;
|
||||
};
|
||||
|
||||
class ImportManager MOZ_FINAL : public nsISupports
|
||||
{
|
||||
typedef nsRefPtrHashtable<nsURIHashKey, ImportLoader> ImportMap;
|
||||
public:
|
||||
ImportManager() {}
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(ImportManager)
|
||||
|
||||
already_AddRefed<ImportLoader> Get(nsIURI* aURI, nsINode* aNode,
|
||||
nsIDocument* aOriginDocument);
|
||||
|
||||
private:
|
||||
ImportMap mImports;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ImportManager_h__
|
@ -70,6 +70,7 @@ EXPORTS.mozilla.dom += [
|
||||
'DOMRect.h',
|
||||
'DOMStringList.h',
|
||||
'EventSource.h',
|
||||
'ImportManager.h',
|
||||
'Link.h',
|
||||
'NodeIterator.h',
|
||||
'ShadowRoot.h',
|
||||
@ -95,6 +96,7 @@ UNIFIED_SOURCES += [
|
||||
'EventSource.cpp',
|
||||
'FileIOObject.cpp',
|
||||
'FragmentOrElement.cpp',
|
||||
'ImportManager.cpp',
|
||||
'Link.cpp',
|
||||
'NodeIterator.cpp',
|
||||
'nsAtomListUtils.cpp',
|
||||
|
@ -1942,6 +1942,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMasterDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImportManager)
|
||||
|
||||
tmp->mRadioGroups.EnumerateRead(RadioGroupsTraverser, &cb);
|
||||
|
||||
@ -2037,6 +2039,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRegistry)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMasterDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportManager)
|
||||
|
||||
tmp->mParentDocument = nullptr;
|
||||
|
||||
@ -4617,6 +4621,10 @@ nsDocument::GetWindowInternal() const
|
||||
if (win) {
|
||||
// mScriptGlobalObject is always the inner window, let's get the outer.
|
||||
win = win->GetOuterWindow();
|
||||
} else if (mMasterDocument) {
|
||||
// For script execution in the imported document we need the window of
|
||||
// the master document.
|
||||
win = mMasterDocument->GetWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@ -7959,6 +7967,9 @@ nsDocument::IsScriptEnabled()
|
||||
NS_ENSURE_TRUE(sm, false);
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(GetInnerWindow());
|
||||
if (!globalObject && mMasterDocument) {
|
||||
globalObject = do_QueryInterface(mMasterDocument->GetInnerWindow());
|
||||
}
|
||||
NS_ENSURE_TRUE(globalObject && globalObject->GetGlobalJSObject(), false);
|
||||
|
||||
return sm->ScriptAllowed(globalObject->GetGlobalJSObject());
|
||||
|
@ -71,6 +71,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIDOMXPathEvaluator.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "ImportManager.h"
|
||||
|
||||
#define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0)
|
||||
#define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1)
|
||||
@ -1246,6 +1247,41 @@ public:
|
||||
mozilla::ErrorResult& rv) MOZ_OVERRIDE;
|
||||
virtual void UseRegistryFromDocument(nsIDocument* aDocument) MOZ_OVERRIDE;
|
||||
|
||||
virtual already_AddRefed<nsIDocument> MasterDocument()
|
||||
{
|
||||
return mMasterDocument ? (nsCOMPtr<nsIDocument>(mMasterDocument)).forget()
|
||||
: (nsCOMPtr<nsIDocument>(this)).forget();
|
||||
}
|
||||
|
||||
virtual void SetMasterDocument(nsIDocument* master)
|
||||
{
|
||||
mMasterDocument = master;
|
||||
}
|
||||
|
||||
virtual bool IsMasterDocument()
|
||||
{
|
||||
return !mMasterDocument;
|
||||
}
|
||||
|
||||
virtual already_AddRefed<mozilla::dom::ImportManager> ImportManager()
|
||||
{
|
||||
if (mImportManager) {
|
||||
MOZ_ASSERT(!mMasterDocument, "Only the master document has ImportManager set");
|
||||
return nsRefPtr<mozilla::dom::ImportManager>(mImportManager).forget();
|
||||
}
|
||||
|
||||
if (mMasterDocument) {
|
||||
return mMasterDocument->ImportManager();
|
||||
}
|
||||
|
||||
// ImportManager is created lazily.
|
||||
// If the manager is not yet set it has to be the
|
||||
// master document and this is the first import in it.
|
||||
// Let's create a new manager.
|
||||
mImportManager = new mozilla::dom::ImportManager();
|
||||
return nsRefPtr<mozilla::dom::ImportManager>(mImportManager).forget();
|
||||
}
|
||||
|
||||
virtual void UnblockDOMContentLoaded() MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
@ -1663,6 +1699,9 @@ private:
|
||||
|
||||
CSPErrorQueue mCSPWebConsoleErrorQueue;
|
||||
|
||||
nsCOMPtr<nsIDocument> mMasterDocument;
|
||||
nsRefPtr<mozilla::dom::ImportManager> mImportManager;
|
||||
|
||||
#ifdef DEBUG
|
||||
protected:
|
||||
bool mWillReparent;
|
||||
|
@ -975,7 +975,8 @@ nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest, void **aOffThreadT
|
||||
|
||||
// The window may have gone away by this point, in which case there's no point
|
||||
// in trying to run the script.
|
||||
nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
|
||||
nsCOMPtr<nsIDocument> master = mDocument->MasterDocument();
|
||||
nsPIDOMWindow *pwin = master->GetInnerWindow();
|
||||
bool runScript = !!pwin;
|
||||
if (runScript) {
|
||||
nsContentUtils::DispatchTrustedEvent(scriptElem->OwnerDoc(),
|
||||
@ -985,7 +986,7 @@ nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest, void **aOffThreadT
|
||||
}
|
||||
|
||||
// Inner window could have gone away after firing beforescriptexecute
|
||||
pwin = mDocument->GetInnerWindow();
|
||||
pwin = master->GetInnerWindow();
|
||||
if (!pwin) {
|
||||
runScript = false;
|
||||
}
|
||||
@ -1047,7 +1048,8 @@ nsScriptLoader::FireScriptEvaluated(nsresult aResult,
|
||||
already_AddRefed<nsIScriptGlobalObject>
|
||||
nsScriptLoader::GetScriptGlobalObject()
|
||||
{
|
||||
nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
|
||||
nsCOMPtr<nsIDocument> master = mDocument->MasterDocument();
|
||||
nsPIDOMWindow *pwin = master->GetInnerWindow();
|
||||
if (!pwin) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1147,18 +1149,27 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
|
||||
|
||||
bool oldProcessingScriptTag = context->GetProcessingScriptTag();
|
||||
context->SetProcessingScriptTag(true);
|
||||
nsresult rv;
|
||||
{
|
||||
// Update our current script.
|
||||
AutoCurrentScriptUpdater scriptUpdater(this, aRequest->mElement);
|
||||
Maybe<AutoCurrentScriptUpdater> masterScriptUpdater;
|
||||
nsCOMPtr<nsIDocument> master = mDocument->MasterDocument();
|
||||
if (master != mDocument) {
|
||||
// If this script belongs to an import document, it will be
|
||||
// executed in the context of the master document. During the
|
||||
// execution currentScript of the master should refer to this
|
||||
// script. So let's update the mCurrentScript of the ScriptLoader
|
||||
// of the master document too.
|
||||
masterScriptUpdater.construct(master->ScriptLoader(),
|
||||
aRequest->mElement);
|
||||
}
|
||||
|
||||
// Update our current script.
|
||||
nsCOMPtr<nsIScriptElement> oldCurrent = mCurrentScript;
|
||||
mCurrentScript = aRequest->mElement;
|
||||
|
||||
JS::CompileOptions options(entryScript.cx());
|
||||
FillCompileOptionsForRequest(aRequest, global, &options);
|
||||
nsresult rv = nsJSUtils::EvaluateString(entryScript.cx(), aSrcBuf, global, options,
|
||||
aOffThreadToken);
|
||||
|
||||
// Put the old script back in case it wants to do anything else.
|
||||
mCurrentScript = oldCurrent;
|
||||
JS::CompileOptions options(entryScript.cx());
|
||||
FillCompileOptionsForRequest(aRequest, global, &options);
|
||||
rv = nsJSUtils::EvaluateString(entryScript.cx(), aSrcBuf, global, options,
|
||||
aOffThreadToken);
|
||||
}
|
||||
|
||||
context->SetProcessingScriptTag(oldProcessingScriptTag);
|
||||
return rv;
|
||||
|
@ -31,7 +31,28 @@ namespace JS {
|
||||
|
||||
class nsScriptLoader : public nsIStreamLoaderObserver
|
||||
{
|
||||
class MOZ_STACK_CLASS AutoCurrentScriptUpdater
|
||||
{
|
||||
public:
|
||||
AutoCurrentScriptUpdater(nsScriptLoader* aScriptLoader,
|
||||
nsIScriptElement* aCurrentScript)
|
||||
: mOldScript(aScriptLoader->mCurrentScript)
|
||||
, mScriptLoader(aScriptLoader)
|
||||
{
|
||||
mScriptLoader->mCurrentScript = aCurrentScript;
|
||||
}
|
||||
~AutoCurrentScriptUpdater()
|
||||
{
|
||||
mScriptLoader->mCurrentScript.swap(mOldScript);
|
||||
}
|
||||
private:
|
||||
nsCOMPtr<nsIScriptElement> mOldScript;
|
||||
nsScriptLoader* mScriptLoader;
|
||||
};
|
||||
|
||||
friend class nsScriptRequestProcessor;
|
||||
friend class AutoCurrentScriptUpdater;
|
||||
|
||||
public:
|
||||
nsScriptLoader(nsIDocument* aDocument);
|
||||
virtual ~nsScriptLoader();
|
||||
|
@ -132,6 +132,8 @@ static uint32_t ToLinkMask(const nsAString& aLink)
|
||||
return nsStyleLinkElement::eNEXT;
|
||||
else if (aLink.EqualsLiteral("alternate"))
|
||||
return nsStyleLinkElement::eALTERNATE;
|
||||
else if (aLink.EqualsLiteral("import"))
|
||||
return nsStyleLinkElement::eHTMLIMPORT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ public:
|
||||
eSTYLESHEET = 0x00000004,
|
||||
eNEXT = 0x00000008,
|
||||
eALTERNATE = 0x00000010,
|
||||
eHTMLIMPORT = 0x00000020
|
||||
};
|
||||
|
||||
// The return value is a bitwise or of 0 or more RelValues
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/HTMLLinkElementBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
@ -19,6 +20,7 @@
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDOMStyleSheet.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsIStyleSheet.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "nsIURL.h"
|
||||
@ -50,6 +52,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLLinkElement,
|
||||
tmp->nsStyleLinkElement::Traverse(cb);
|
||||
tmp->Link::Traverse(cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRelList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImportLoader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLLinkElement,
|
||||
@ -57,6 +60,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLLinkElement,
|
||||
tmp->nsStyleLinkElement::Unlink();
|
||||
tmp->Link::Unlink();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRelList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportLoader)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(HTMLLinkElement, Element)
|
||||
@ -148,6 +152,9 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal;
|
||||
nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update));
|
||||
|
||||
void (HTMLLinkElement::*updateImport)() = &HTMLLinkElement::UpdateImport;
|
||||
nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, updateImport));
|
||||
|
||||
CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMLinkAdded"));
|
||||
|
||||
return rv;
|
||||
@ -188,6 +195,7 @@ HTMLLinkElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
||||
|
||||
UpdateStyleSheetInternal(oldDoc, oldShadowRoot);
|
||||
UpdateImport();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -241,6 +249,63 @@ HTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc,
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::UpdateImport()
|
||||
{
|
||||
if (!Preferences::GetBool("dom.webcomponents.enabled")) {
|
||||
// For now imports are hidden behind a pref...
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. link node should be attached to the document.
|
||||
nsCOMPtr<nsIDocument> doc = GetCurrentDoc();
|
||||
if (!doc) {
|
||||
// We might have been just removed from the document, so
|
||||
// let's remove ourself from the list of link nodes of
|
||||
// the import and reset mImportLoader.
|
||||
if (mImportLoader) {
|
||||
mImportLoader->RemoveLinkElement(this);
|
||||
mImportLoader = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Until the script execution order is not sorted out for nested cases
|
||||
// let's not allow them.
|
||||
if (!doc->IsMasterDocument()) {
|
||||
nsContentUtils::LogSimpleConsoleError(
|
||||
NS_LITERAL_STRING("Nested imports are not supported yet"),
|
||||
"Imports");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. rel type should be import.
|
||||
nsAutoString rel;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel);
|
||||
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel);
|
||||
if (!(linkTypes & eHTMLIMPORT)) {
|
||||
mImportLoader = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = GetHrefURI();
|
||||
if (!uri) {
|
||||
mImportLoader = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<ImportManager> manager = doc->ImportManager();
|
||||
MOZ_ASSERT(manager, "ImportManager should be created lazily when needed");
|
||||
|
||||
{
|
||||
// The load even might fire sooner than we could set mImportLoader so
|
||||
// we must use async event and a scriptBlocker here.
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
// CORS check will happen at the start of the load.
|
||||
mImportLoader = manager->Get(uri, this, doc);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
@ -265,9 +330,17 @@ HTMLLinkElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
aName == nsGkAtoms::media ||
|
||||
aName == nsGkAtoms::type)) {
|
||||
bool dropSheet = false;
|
||||
if (aName == nsGkAtoms::rel && GetSheet()) {
|
||||
if (aName == nsGkAtoms::rel) {
|
||||
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(aValue);
|
||||
dropSheet = !(linkTypes & nsStyleLinkElement::eSTYLESHEET);
|
||||
if (GetSheet()) {
|
||||
dropSheet = !(linkTypes & nsStyleLinkElement::eSTYLESHEET);
|
||||
} else if (linkTypes & eHTMLIMPORT) {
|
||||
UpdateImport();
|
||||
}
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::href) {
|
||||
UpdateImport();
|
||||
}
|
||||
|
||||
UpdateStyleSheetInternal(nullptr, nullptr,
|
||||
@ -288,13 +361,18 @@ HTMLLinkElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
||||
aNotify);
|
||||
// Since removing href or rel makes us no longer link to a
|
||||
// stylesheet, force updates for those too.
|
||||
if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None &&
|
||||
(aAttribute == nsGkAtoms::href ||
|
||||
aAttribute == nsGkAtoms::rel ||
|
||||
aAttribute == nsGkAtoms::title ||
|
||||
aAttribute == nsGkAtoms::media ||
|
||||
aAttribute == nsGkAtoms::type)) {
|
||||
UpdateStyleSheetInternal(nullptr, nullptr, true);
|
||||
if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::href ||
|
||||
aAttribute == nsGkAtoms::rel ||
|
||||
aAttribute == nsGkAtoms::title ||
|
||||
aAttribute == nsGkAtoms::media ||
|
||||
aAttribute == nsGkAtoms::type) {
|
||||
UpdateStyleSheetInternal(nullptr, nullptr, true);
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::href ||
|
||||
aAttribute == nsGkAtoms::rel) {
|
||||
UpdateImport();
|
||||
}
|
||||
}
|
||||
|
||||
// The ordering of the parent class's UnsetAttr call and Link::ResetLinkState
|
||||
@ -444,5 +522,11 @@ HTMLLinkElement::WrapNode(JSContext* aCx)
|
||||
return HTMLLinkElementBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocument>
|
||||
HTMLLinkElement::GetImport()
|
||||
{
|
||||
return mImportLoader ? mImportLoader->GetImport() : nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/Link.h"
|
||||
#include "ImportManager.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLLinkElement.h"
|
||||
#include "nsStyleLinkElement.h"
|
||||
@ -42,6 +43,8 @@ public:
|
||||
void LinkAdded();
|
||||
void LinkRemoved();
|
||||
|
||||
void UpdateImport();
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
|
||||
virtual nsresult PostHandleEvent(
|
||||
@ -134,6 +137,12 @@ public:
|
||||
SetHTMLAttr(nsGkAtoms::target, aTarget, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDocument> GetImport();
|
||||
already_AddRefed<ImportLoader> GetImportLoader()
|
||||
{
|
||||
return nsRefPtr<ImportLoader>(mImportLoader).forget();
|
||||
}
|
||||
|
||||
protected:
|
||||
// nsStyleLinkElement
|
||||
virtual already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline) MOZ_OVERRIDE;
|
||||
@ -148,6 +157,8 @@ protected:
|
||||
virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
|
||||
virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
|
||||
nsRefPtr<nsDOMTokenList > mRelList;
|
||||
private:
|
||||
nsRefPtr<ImportLoader> mImportLoader;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
22
content/html/content/test/file_imports_basics.html
Normal file
22
content/html/content/test/file_imports_basics.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div id="foo">bar</div>
|
||||
<script>
|
||||
counter++;
|
||||
var importDone = true;
|
||||
is(document.currentScript.ownerDocument.getElementById("foo").textContent, "bar",
|
||||
"currentScript.ownerDocument works in imported document,");
|
||||
try{
|
||||
document.currentScript.ownerDocument.open();
|
||||
document.currentScript.ownerDocument.write("<h1>This should not show up!</h1>");
|
||||
document.currentScript.ownerDocument.close();
|
||||
ok(false, "document.write should have thrown (import)")
|
||||
} catch (e) {
|
||||
ok(true, "document.write has thrown (import)")
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -144,6 +144,7 @@ support-files =
|
||||
file_iframe_sandbox_window_top_navigation_pass.html
|
||||
file_iframe_sandbox_window_top_navigation_fail.html
|
||||
file_iframe_sandbox_worker.js
|
||||
file_imports_basics.html
|
||||
file_srcdoc-2.html
|
||||
file_srcdoc.html
|
||||
form_submit_server.sjs
|
||||
@ -448,6 +449,7 @@ skip-if = buildapp == 'b2g' || e10s # b2g(multiple concurrent window.open()s fai
|
||||
[test_iframe_sandbox_workers.html]
|
||||
[test_img_attributes_reflection.html]
|
||||
[test_imageSrcSet.html]
|
||||
[test_imports_basics.html]
|
||||
[test_li_attributes_reflection.html]
|
||||
[test_link_attributes_reflection.html]
|
||||
[test_link_sizes.html]
|
||||
|
68
content/html/content/test/test_imports_basics.html
Normal file
68
content/html/content/test/test_imports_basics.html
Normal file
@ -0,0 +1,68 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=877072
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 877072</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=877072">Mozilla Bug 877072</a>
|
||||
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var loadEventFired = false;
|
||||
var errorEventFired = false;
|
||||
var counter = 0;
|
||||
function loaded() {
|
||||
loadEventFired = true;
|
||||
}
|
||||
function failed() {
|
||||
errorEventFired = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="import" href="file_imports_basics.html" id="import1" onload="loaded()" onerror="failed()"></link>
|
||||
|
||||
<script type="text/javascript">
|
||||
ok(importDone, "Script of the imported document runned before this script");
|
||||
ok(loadEventFired, "Load eventhandler works");
|
||||
ok(!errorEventFired, "There were no error event fired");
|
||||
|
||||
var import1 = document.getElementById("import1").import;
|
||||
is(import1.getElementById("foo").textContent, "bar",
|
||||
"import property of link import works");
|
||||
|
||||
try{
|
||||
import1.open();
|
||||
import1.write("<h1>This should not show up!</h1>");
|
||||
import1.close();
|
||||
} catch (e) {
|
||||
ok(true, "import.open/write should throw");
|
||||
}
|
||||
|
||||
// Let's add dynamically a new link import with the same URI
|
||||
var link = document.createElement("link");
|
||||
link.setAttribute("id", "inserted");
|
||||
link.setAttribute("rel", "import");
|
||||
link.setAttribute("href", "file_imports_basics.html");
|
||||
function loaded2() {
|
||||
ok(true, "Load event is fired for link import that refers to an already loaded import");
|
||||
is(counter, 1, "Adding another link referring to the same import, does not load it twice");
|
||||
is(document.getElementById("inserted").import.getElementById("foo").textContent, "bar",
|
||||
"import property of dynamic link import works");
|
||||
SimpleTest.finish();
|
||||
};
|
||||
link.setAttribute("onload", "loaded2()");
|
||||
function failed2() {
|
||||
ok(false, "You should not reach this code");
|
||||
SimpleTest.finish();
|
||||
};
|
||||
link.setAttribute("onerror", "failed2()");
|
||||
document.body.appendChild(link);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -547,7 +547,8 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
||||
!strcmp(aCommand, "external-resource");
|
||||
bool viewSource = !strcmp(aCommand, "view-source");
|
||||
bool asData = !strcmp(aCommand, kLoadAsData);
|
||||
if(!(view || viewSource || asData)) {
|
||||
bool import = !strcmp(aCommand, "import");
|
||||
if (!(view || viewSource || asData || import)) {
|
||||
MOZ_ASSERT(false, "Bad parser command");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
@ -1370,7 +1371,7 @@ nsHTMLDocument::Open(JSContext* cx,
|
||||
{
|
||||
NS_ASSERTION(nsContentUtils::CanCallerAccess(static_cast<nsIDOMHTMLDocument*>(this)),
|
||||
"XOW should have caught this!");
|
||||
if (!IsHTML() || mDisableDocWrite) {
|
||||
if (!IsHTML() || mDisableDocWrite || !IsMasterDocument()) {
|
||||
// No calling document.open() on XHTML
|
||||
rv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
@ -1772,7 +1773,7 @@ nsHTMLDocument::WriteCommon(JSContext *cx,
|
||||
(mWriteLevel > NS_MAX_DOCUMENT_WRITE_DEPTH || mTooDeepWriteRecursion);
|
||||
NS_ENSURE_STATE(!mTooDeepWriteRecursion);
|
||||
|
||||
if (!IsHTML() || mDisableDocWrite) {
|
||||
if (!IsHTML() || mDisableDocWrite || !IsMasterDocument()) {
|
||||
// No calling document.write*() on XHTML!
|
||||
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
|
@ -31,6 +31,7 @@ interface HTMLLinkElement : HTMLElement {
|
||||
[PutForwards=value] readonly attribute DOMSettableTokenList sizes;
|
||||
};
|
||||
HTMLLinkElement implements LinkStyle;
|
||||
HTMLLinkElement implements LinkImport;
|
||||
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
|
||||
partial interface HTMLLinkElement {
|
||||
|
13
dom/webidl/LinkImport.webidl
Normal file
13
dom/webidl/LinkImport.webidl
Normal file
@ -0,0 +1,13 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://www.w3.org/TR/2013/WD-html-imports-20130514/
|
||||
*/
|
||||
|
||||
[NoInterfaceObject]
|
||||
interface LinkImport {
|
||||
readonly attribute Document? import;
|
||||
};
|
@ -224,6 +224,7 @@ WEBIDL_FILES = [
|
||||
'KeyboardEvent.webidl',
|
||||
'KeyEvent.webidl',
|
||||
'LegacyQueryInterface.webidl',
|
||||
'LinkImport.webidl',
|
||||
'LinkStyle.webidl',
|
||||
'LocalMediaStream.webidl',
|
||||
'Location.webidl',
|
||||
|
@ -79,6 +79,7 @@ nsHtml5Parser::SetCommand(const char* aCommand)
|
||||
NS_ASSERTION(!strcmp(aCommand, "view") ||
|
||||
!strcmp(aCommand, "view-source") ||
|
||||
!strcmp(aCommand, "external-resource") ||
|
||||
!strcmp(aCommand, "import") ||
|
||||
!strcmp(aCommand, kLoadAsData),
|
||||
"Unsupported parser command");
|
||||
}
|
||||
@ -577,7 +578,8 @@ nsHtml5Parser::MarkAsNotScriptCreated(const char* aCommand)
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
NS_ASSERTION(!nsCRT::strcmp(aCommand, "view") ||
|
||||
!nsCRT::strcmp(aCommand, "external-resource"),
|
||||
!nsCRT::strcmp(aCommand, "external-resource") ||
|
||||
!nsCRT::strcmp(aCommand, "import"),
|
||||
"Unsupported parser command!");
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user