| Index: Source/WebCore/bindings/dart/DartApplicationLoader.cpp
|
| diff --git a/Source/WebCore/bindings/dart/DartApplicationLoader.cpp b/Source/WebCore/bindings/dart/DartApplicationLoader.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b55f8e0e477b962c0a64c6a0b047ab9993f47ac4
|
| --- /dev/null
|
| +++ b/Source/WebCore/bindings/dart/DartApplicationLoader.cpp
|
| @@ -0,0 +1,420 @@
|
| +// Copyright (c) 2009, Google Inc.
|
| +// All rights reserved.
|
| +//
|
| +// Redistribution and use in source and binary forms, with or without
|
| +// modification, are permitted provided that the following conditions are
|
| +// met:
|
| +//
|
| +// * Redistributions of source code must retain the above copyright
|
| +// notice, this list of conditions and the following disclaimer.
|
| +// * Redistributions in binary form must reproduce the above
|
| +// copyright notice, this list of conditions and the following disclaimer
|
| +// in the documentation and/or other materials provided with the
|
| +// distribution.
|
| +// * Neither the name of Google Inc. nor the names of its
|
| +// contributors may be used to endorse or promote products derived from
|
| +// this software without specific prior written permission.
|
| +//
|
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +#include "config.h"
|
| +#include "DartApplicationLoader.h"
|
| +
|
| +#include "CachedResourceClient.h"
|
| +#include "CachedResourceLoader.h"
|
| +#include "DOMWindow.h"
|
| +#include "DartDOMWrapper.h"
|
| +#include "DartHTMLLibrarySource.h"
|
| +#include "DartHTMLImplLibrarySource.h"
|
| +#include "DartIsolateState.h"
|
| +#include "DartJSONLibrarySource.h"
|
| +#include "DartUtilities.h"
|
| +#include "Document.h"
|
| +#include "Frame.h"
|
| +#include "ScriptCallStack.h"
|
| +#include "ScriptSourceCode.h"
|
| +
|
| +#include <dart_api.h>
|
| +
|
| +namespace WebCore {
|
| +
|
| +DartApplicationLoader::DartApplicationLoader(Document* document, NPObject* layoutTestController)
|
| + : m_document(document)
|
| + , m_layoutTestController(layoutTestController)
|
| + , m_libraryUrl()
|
| + , m_importedLibraries()
|
| + , m_importersForSource()
|
| + , m_sources()
|
| + , m_mainScriptHasBeenLoaded(false)
|
| +{
|
| +}
|
| +
|
| +void DartApplicationLoader::load(const String& url, const String& source)
|
| +{
|
| + DartApiScope dartApiScope;
|
| +
|
| + if (m_importedLibraries.isEmpty() && m_importersForSource.isEmpty())
|
| + loadScript(url, source);
|
| + else {
|
| + if (m_importedLibraries.contains(url)) {
|
| + loadLibrary(url, source);
|
| + m_importedLibraries.remove(url);
|
| + }
|
| +
|
| + if (m_importersForSource.contains(url)) {
|
| + loadSource(url, source);
|
| + m_importersForSource.remove(url);
|
| + }
|
| + }
|
| +
|
| + m_sources.add(url, source);
|
| +
|
| + if (m_importedLibraries.isEmpty() && m_importersForSource.isEmpty() && m_mainScriptHasBeenLoaded)
|
| + callEntryPoint();
|
| +}
|
| +
|
| +void DartApplicationLoader::importBuiltinLibrary(const String& url, const String& source)
|
| +{
|
| + Dart_Handle result = Dart_LoadLibrary(DartUtilities::stringToDartString(url), DartUtilities::stringToDartString(source));
|
| + if (Dart_IsError(result)) {
|
| + DartUtilities::reportProblem(m_document, result);
|
| + return;
|
| + }
|
| + m_sources.add(url, source);
|
| +}
|
| +
|
| +IsolateToDartApplicationLoaderMap& isolateToDartApplicationLoaderMap()
|
| +{
|
| + DEFINE_STATIC_LOCAL(IsolateToDartApplicationLoaderMap, map, ());
|
| + return map;
|
| +}
|
| +
|
| +static DartApplicationLoader* currentAppLoader()
|
| +{
|
| + IsolateToDartApplicationLoaderMap::iterator it = isolateToDartApplicationLoaderMap().find(Dart_CurrentIsolate());
|
| + ASSERT(it != isolateToDartApplicationLoaderMap().end());
|
| + return it->second;
|
| +}
|
| +
|
| +template <class Loader>
|
| +class ScriptLoader {
|
| +public:
|
| + static void loadScript(const String& url, const String& source, ScriptExecutionContext* context)
|
| + {
|
| + Dart_Handle result = Dart_LoadScript(
|
| + DartUtilities::stringToDartString(url),
|
| + DartUtilities::stringToDartString(source),
|
| + &handler);
|
| + if (Dart_IsError(result))
|
| + DartUtilities::reportProblem(context, result);
|
| + }
|
| +
|
| +private:
|
| + static Dart_Handle handler(Dart_LibraryTag tag, Dart_Handle library, Dart_Handle urlHandle)
|
| + {
|
| + ASSERT(Dart_IsLibrary(library));
|
| +
|
| + String url = DartUtilities::dartStringToString(urlHandle);
|
| +
|
| + Dart_Handle libraryURLHandle = Dart_LibraryUrl(library);
|
| + ASSERT(!Dart_IsError(libraryURLHandle));
|
| + const String libraryURL = DartUtilities::dartStringToString(libraryURLHandle);
|
| +
|
| + if (tag == kCanonicalizeUrl) {
|
| + const KURL canonical = KURL(KURL(KURL(), libraryURL), url);
|
| + return DartUtilities::stringToDartString(canonical.string());
|
| + }
|
| +
|
| + return Loader::load(tag, library, libraryURL, url);
|
| + }
|
| +};
|
| +
|
| +struct InitialLoader {
|
| + static Dart_Handle load(Dart_LibraryTag tag, Dart_Handle library, const String& libraryUrl, const String& importedUrl)
|
| + {
|
| + currentAppLoader()->triggerImport(libraryUrl, importedUrl, tag);
|
| + return Dart_NewBoolean(true);
|
| + }
|
| +};
|
| +
|
| +void DartApplicationLoader::loadScript(const String& url, const String& source)
|
| +{
|
| + ASSERT(m_importedLibraries.isEmpty());
|
| + ASSERT(m_importersForSource.isEmpty());
|
| + m_libraryUrl = url;
|
| + ScriptLoader<InitialLoader>::loadScript(url, source, m_document);
|
| + m_mainScriptHasBeenLoaded = true;
|
| +}
|
| +
|
| +void DartApplicationLoader::loadSource(const String& url, const String& source)
|
| +{
|
| + ASSERT(m_importersForSource.contains(url));
|
| + const UrlSet* importers = m_importersForSource.find(url)->second;
|
| + Dart_Handle dartUrl = DartUtilities::stringToDartString(url);
|
| + Dart_Handle dartSource = DartUtilities::stringToDartString(source);
|
| + for (UrlSet::iterator iter = importers->begin(); iter != importers->end(); ++iter) {
|
| + Dart_Handle library = Dart_LookupLibrary(DartUtilities::stringToDartString(*iter));
|
| + if (Dart_IsError(library)) {
|
| + DartUtilities::reportProblem(m_document, library);
|
| + return;
|
| + }
|
| + Dart_Handle result = Dart_LoadSource(library, dartUrl, dartSource);
|
| + if (Dart_IsError(result)) {
|
| + DartUtilities::reportProblem(m_document, result);
|
| + return;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void DartApplicationLoader::loadLibrary(const String& url, const String& source)
|
| +{
|
| + ASSERT(m_importedLibraries.contains(url));
|
| + Dart_Handle result = Dart_LoadLibrary(DartUtilities::stringToDartString(url), DartUtilities::stringToDartString(source));
|
| + if (Dart_IsError(result))
|
| + DartUtilities::reportProblem(m_document, result);
|
| +}
|
| +
|
| +static void invokeMain(Document* document, Dart_Handle topLevelLibrary)
|
| +{
|
| + Dart_Handle result = Dart_InvokeStatic(topLevelLibrary, Dart_NewString(""), Dart_NewString("main"), 0, 0);
|
| + if (Dart_IsError(result))
|
| + DartUtilities::reportProblem(document, result);
|
| +}
|
| +
|
| +class ScriptStarter : public EventListener {
|
| +public:
|
| + static PassRefPtr<ScriptStarter> create(Dart_Isolate isolate, Dart_Handle topLevelLibrary)
|
| + {
|
| + return adoptRef(new ScriptStarter(isolate, Dart_NewPersistentHandle(topLevelLibrary)));
|
| + }
|
| +
|
| + virtual ~ScriptStarter()
|
| + {
|
| + DartIsolateState::Scope scope(m_isolate);
|
| + DartApiScope apiScope;
|
| + Dart_DeletePersistentHandle(m_topLevelLibrary);
|
| + }
|
| +
|
| + virtual void handleEvent(ScriptExecutionContext* context, Event*)
|
| + {
|
| + ASSERT(context->isDocument());
|
| + Document* document = static_cast<Document*>(context);
|
| +
|
| + // this gets removed below, so protect it while handler runs.
|
| + RefPtr<ScriptStarter> protect = this;
|
| + document->domWindow()->removeEventListener(String("DOMContentLoaded"), this, false);
|
| +
|
| + DartIsolateState::Scope scope(m_isolate);
|
| + DartApiScope apiScope;
|
| + invokeMain(document, m_topLevelLibrary);
|
| + }
|
| +
|
| + virtual bool operator==(const EventListener& other)
|
| + {
|
| + return this == &other;
|
| + }
|
| +
|
| +private:
|
| + ScriptStarter(Dart_Isolate isolate, Dart_Handle topLevelLibrary)
|
| + : EventListener(EventListener::NativeEventListenerType)
|
| + , m_isolate(isolate)
|
| + , m_topLevelLibrary(topLevelLibrary)
|
| + {
|
| + }
|
| +
|
| + Dart_Isolate m_isolate;
|
| + Dart_Handle m_topLevelLibrary;
|
| +};
|
| +
|
| +void DartApplicationLoader::callEntryPoint()
|
| +{
|
| + Dart_Handle result = Dart_CompileAll();
|
| + if (Dart_IsError(result)) {
|
| + DartUtilities::reportProblem(m_document, result);
|
| + return;
|
| + }
|
| +
|
| + if (m_layoutTestController) {
|
| + Dart_Handle npObject = toDartValue(m_layoutTestController);
|
| + result = Dart_InvokeStatic(domLibrary(), Dart_NewString("LayoutTestController"), Dart_NewString("_initLayoutTestController"), 1, &npObject);
|
| + ASSERT(!Dart_IsError(result));
|
| + }
|
| +
|
| + if (m_document->readyState() == "loading")
|
| + m_document->domWindow()->addEventListener(String("DOMContentLoaded"), ScriptStarter::create(Dart_CurrentIsolate(), topLevelLibrary()), false);
|
| + else
|
| + invokeMain(m_document, topLevelLibrary());
|
| +}
|
| +
|
| +Dart_Handle DartApplicationLoader::topLevelLibrary()
|
| +{
|
| + Dart_Handle library = Dart_LookupLibrary(DartUtilities::stringToDartString(m_libraryUrl));
|
| + ASSERT(!Dart_IsError(library));
|
| + return library;
|
| +}
|
| +
|
| +Dart_Handle DartApplicationLoader::domLibrary()
|
| +{
|
| + Dart_Handle library = Dart_LookupLibrary(Dart_NewString(DartUtilities::domLibraryName));
|
| + ASSERT(!Dart_IsError(library));
|
| + return library;
|
| +}
|
| +
|
| +class ScriptLoadCallback : public CachedResourceClient {
|
| +public:
|
| + ScriptLoadCallback(DartApplicationLoader* loader, CachedScript* cachedScript, Dart_Isolate isolate)
|
| + : m_loader(loader),
|
| + m_cachedScript(cachedScript),
|
| + m_isolate(isolate)
|
| + {
|
| + }
|
| +
|
| + virtual void notifyFinished(CachedResource* cachedResource)
|
| + {
|
| + ASSERT(cachedResource->type() == CachedResource::Script);
|
| + ASSERT(cachedResource == m_cachedScript.get());
|
| + ASSERT(WTF::isMainThread());
|
| + if (cachedResource->errorOccurred())
|
| + m_loader->scriptLoadError(cachedResource->url());
|
| + else if (cachedResource->wasCanceled())
|
| + m_loader->scriptLoadCancelled(cachedResource->url());
|
| + else {
|
| + ScriptSourceCode source(m_cachedScript.get());
|
| + m_loader->scriptLoaded(source, m_isolate);
|
| + }
|
| + m_cachedScript->removeClient(this);
|
| + delete this;
|
| + }
|
| +
|
| + private:
|
| + RefPtr<DartApplicationLoader> m_loader;
|
| + CachedResourceHandle<CachedScript> m_cachedScript;
|
| + Dart_Isolate m_isolate;
|
| +};
|
| +
|
| +
|
| +void DartApplicationLoader::triggerImport(const String& libraryUrl, const String& importedUrl, Dart_LibraryTag tag)
|
| +{
|
| + if (importedUrl == "dart:json") {
|
| + ASSERT(tag == kImportTag);
|
| + importBuiltinLibrary(importedUrl, dartJSONLibrarySource);
|
| + return;
|
| + }
|
| + if (importedUrl == "dart:html") {
|
| + ASSERT(tag == kImportTag);
|
| + importBuiltinLibrary(importedUrl, dartHTMLLibrarySource);
|
| + return;
|
| + }
|
| + if (importedUrl == "dart:htmlimpl") {
|
| + ASSERT(tag == kImportTag);
|
| + importBuiltinLibrary(importedUrl, dartHTMLImplLibrarySource);
|
| + return;
|
| + }
|
| + ASSERT(importedUrl != "dart:dom");
|
| +
|
| + // Record the importer.
|
| + if (tag == kImportTag)
|
| + m_importedLibraries.add(importedUrl);
|
| + else if (tag == kSourceTag)
|
| + add(m_importersForSource, importedUrl, libraryUrl);
|
| + else
|
| + ASSERT_NOT_REACHED();
|
| +
|
| + // Request loading of script dependencies.
|
| + CachedResourceLoader* loader = m_document->cachedResourceLoader();
|
| + ResourceRequest request(m_document->completeURL(importedUrl));
|
| + // FIXME: what about charset for this script, maybe use charset of initial script tag?
|
| + CachedScript* cachedScript = loader->requestScript(request, "utf-8");
|
| +
|
| + cachedScript->addClient(new ScriptLoadCallback(this, cachedScript, Dart_CurrentIsolate()));
|
| +}
|
| +
|
| +void DartApplicationLoader::scriptLoadError(const KURL& url)
|
| +{
|
| + // FIXME: source file info (must be captured when requesting resource).
|
| + String sourceFile = "FIXME";
|
| + // FIXME: line number info (must be captured when requesting resource).
|
| + int lineNumber = 0;
|
| + // FIXME: call stack info (must be captured when requesting resource).
|
| + RefPtr<ScriptCallStack> callStack;
|
| + String errorMessage = "Cannot load Dart script " + url.string();
|
| + m_document->reportException(errorMessage, lineNumber, sourceFile, callStack);
|
| + // FIXME: shall we let VM know, so it can inform application some of its
|
| + // resources cannot be loaded?
|
| +}
|
| +
|
| +void DartApplicationLoader::scriptLoadCancelled(const KURL& url)
|
| +{
|
| + // FIXME: shall we let VM know, so it can inform application some of its
|
| + // resources cannot be loaded?
|
| +}
|
| +
|
| +void DartApplicationLoader::scriptLoaded(const ScriptSourceCode& script, Dart_Isolate isolate)
|
| +{
|
| + // FIXME: we can get rid of imported libs and sources map.
|
| + DartIsolateState::Scope scope(isolate);
|
| + load(script.url(), script.source());
|
| +}
|
| +
|
| +Dart_Handle DartApplicationLoader::reinject(Dart_Handle library, const String& libraryUrl, const String& importedUrl, Dart_LibraryTag tag)
|
| +{
|
| + ASSERT(m_sources.contains(importedUrl));
|
| + const String& source = m_sources.get(importedUrl);
|
| +
|
| + Dart_Handle dartSource = DartUtilities::stringToDartString(source);
|
| + if (tag == kImportTag) {
|
| + Dart_Handle result = Dart_LoadLibrary(DartUtilities::stringToDartString(importedUrl), dartSource);
|
| + if (Dart_IsError(result))
|
| + return result;
|
| + } else if (tag == kSourceTag) {
|
| + Dart_Handle result = Dart_LoadSource(library, DartUtilities::stringToDartString(importedUrl), dartSource);
|
| + if (Dart_IsError(result))
|
| + return result;
|
| + } else
|
| + ASSERT_NOT_REACHED();
|
| +
|
| + return Dart_NewBoolean(true);
|
| +}
|
| +
|
| +void DartApplicationLoader::add(UrlMultiMap& map, const String& key, const String& value)
|
| +{
|
| + // We should never have a self dependence.
|
| + ASSERT(key != value);
|
| + UrlMultiMap::iterator iter = map.find(key);
|
| + if (iter == map.end())
|
| + iter = map.add(key, new UrlSet()).first;
|
| + UrlSet* set = iter->second;
|
| + set->add(value);
|
| +}
|
| +
|
| +struct ReinjectLoader {
|
| + static Dart_Handle load(Dart_LibraryTag tag, Dart_Handle library, const String& libraryUrl, const String& importedUrl)
|
| + {
|
| + return currentAppLoader()->reinject(library, libraryUrl, importedUrl, tag);
|
| + }
|
| +};
|
| +
|
| +void DartApplicationLoader::reinjectSources()
|
| +{
|
| + ASSERT(!isLoadingMainIsolate());
|
| +
|
| + // FIXME: propagate flags as well.
|
| +
|
| + // Set proper dart loader for child isolate.
|
| + isolateToDartApplicationLoaderMap().set(Dart_CurrentIsolate(), this);
|
| +
|
| + ASSERT(m_sources.contains(m_libraryUrl));
|
| + ScriptLoader<ReinjectLoader>::loadScript(m_libraryUrl, m_sources.get(m_libraryUrl), m_document);
|
| +}
|
| +
|
| +}
|
|
|