| Index: Source/bindings/dart/DartAsyncLoader.cpp
|
| diff --git a/Source/bindings/dart/DartAsyncLoader.cpp b/Source/bindings/dart/DartAsyncLoader.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f9affeb6bdb2149fe8e2136e598368f356d64f95
|
| --- /dev/null
|
| +++ b/Source/bindings/dart/DartAsyncLoader.cpp
|
| @@ -0,0 +1,263 @@
|
| +// Copyright (c) 2013, 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 "bindings/dart/DartAsyncLoader.h"
|
| +
|
| +#include "FetchInitiatorTypeNames.h"
|
| +#include "bindings/dart/DartUtilities.h"
|
| +#include "bindings/v8/ScriptSourceCode.h"
|
| +#include "core/dom/Document.h"
|
| +#include "core/dom/ScriptLoader.h"
|
| +#include "core/fetch/FetchRequest.h"
|
| +#include "core/fetch/ResourceClient.h"
|
| +#include "core/fetch/ResourceFetcher.h"
|
| +#include "core/fetch/ScriptResource.h"
|
| +#include "core/inspector/ScriptCallStack.h"
|
| +
|
| +#include <dart_api.h>
|
| +
|
| +namespace WebCore {
|
| +
|
| +static const unsigned dartTypeID = 0xDAADDAAD;
|
| +
|
| +void DartAsyncLoader::LoadCallback::reportError(const String& error, const String& url)
|
| +{
|
| + m_originDocument->logExceptionToConsole(error + ": " + url, url, 0, 0, 0);
|
| + if (m_scriptLoader)
|
| + m_scriptLoader->dispatchErrorEvent();
|
| +}
|
| +
|
| +ResourcePtr<ScriptResource> DartAsyncLoader::LoadCallback::requestScript(FetchRequest& request)
|
| +{
|
| + return m_originDocument->fetcher()->requestScript(request);
|
| +}
|
| +
|
| +
|
| +DartAsyncLoader::DartAsyncLoader(const String& url, PassRefPtr<DartAsyncLoader::LoadCallback> loadCallback)
|
| + : m_loadCallback(loadCallback)
|
| + , m_mainScriptFetched(false)
|
| +{
|
| + Document* document = m_loadCallback->document();
|
| + char* error;
|
| +
|
| + const KURL canonical = KURL(document->baseURL(), url);
|
| + m_topUrl = canonical.string();
|
| +
|
| + DartDOMData* domData = new DartDOMData(document, false);
|
| + domData->setAsyncLoader(adoptRef(this));
|
| +
|
| + const uint8_t* snapshot = DartUtilities::fullSnapshot(document->frame());
|
| + m_parseIsolate = Dart_CreateIsolate("dartium.fetch", "", snapshot, domData, &error);
|
| + if (!m_parseIsolate)
|
| + m_loadCallback->reportError(error, url);
|
| +
|
| + Dart_Handle result = Dart_SetLibraryTagHandler(&libraryTagHandlerCallback);
|
| + ASSERT(!Dart_IsError(result));
|
| + UNUSED_PARAM(result);
|
| +
|
| + m_pendingLibraries.add(m_topUrl);
|
| +}
|
| +
|
| +DartAsyncLoader::~DartAsyncLoader()
|
| +{
|
| + m_loadCallback = 0;
|
| +}
|
| +
|
| +void DartAsyncLoader::findDependences(const String& url, const String& source, intptr_t lineNumber)
|
| +{
|
| + ASSERT(m_pendingLibraries.contains(url) || m_pendingSource.contains(url));
|
| +
|
| + DartIsolateScope isolateScope(m_parseIsolate);
|
| + DartApiScope dartApiScope;
|
| +
|
| + if (!m_mainScriptFetched) {
|
| + ASSERT(m_topUrl == url);
|
| + m_topSource = source;
|
| + m_lineNumber = lineNumber;
|
| + m_mainScriptFetched = true;
|
| + }
|
| +
|
| + if (m_pendingLibraries.contains(url)) {
|
| + processLibrary(url, source);
|
| + m_pendingLibraries.remove(url);
|
| + } else {
|
| + ASSERT(m_pendingSource.contains(url));
|
| + // No imports or parts, so no need to process further.
|
| + m_pendingSource.remove(url);
|
| + }
|
| +}
|
| +
|
| +void DartAsyncLoader::reportError(Dart_Handle error, const String& url)
|
| +{
|
| + reportError(Dart_GetError(error), url);
|
| +}
|
| +
|
| +void DartAsyncLoader::processLibrary(const String& url, const String& source)
|
| +{
|
| + ASSERT(m_pendingLibraries.contains(url));
|
| +
|
| + Dart_Handle result = Dart_LoadLibrary(DartUtilities::stringToDartString(url), DartUtilities::convertSourceString(source));
|
| + if (Dart_IsError(result))
|
| + reportError(result, url);
|
| +}
|
| +
|
| +void DartAsyncLoader::process(const String& url, const String& source, intptr_t lineNumber)
|
| +{
|
| + ASSERT(!m_urlSourceMap.contains(url));
|
| + m_urlSourceMap.add(url, source);
|
| +
|
| + findDependences(url, source, lineNumber);
|
| + if (ready()) {
|
| + // All dependences are in.
|
| + RefPtr<DartAsyncLoader> guard(this);
|
| + m_loadCallback->ready(guard);
|
| +
|
| + // Free this loader and its isolate.
|
| + Dart_EnterIsolate(m_parseIsolate);
|
| + DartDOMData::current()->setAsyncLoader(0);
|
| + Dart_ShutdownIsolate();
|
| + }
|
| +}
|
| +
|
| +Dart_Handle DartAsyncLoader::libraryTagHandlerCallback(Dart_LibraryTag tag, Dart_Handle library, Dart_Handle urlHandle)
|
| +{
|
| + ASSERT(Dart_CurrentIsolate());
|
| + ASSERT(Dart_IsLibrary(library));
|
| +
|
| + const String url = DartUtilities::toString(urlHandle);
|
| +
|
| + if (tag == Dart_kCanonicalizeUrl) {
|
| + // If a dart application calls spawnUri, the DartVM will call this
|
| + // libraryTagHandler to canonicalize the url.
|
| + // DartDOMData::current()->scriptLoader() may be 0 at this point.
|
| + return DartUtilities::canonicalizeUrl(library, urlHandle, url);
|
| + }
|
| +
|
| + RefPtr<DartAsyncLoader> loader = DartDOMData::current()->asyncLoader();
|
| + ASSERT(loader);
|
| +
|
| + if (!url.startsWith("dart:")) {
|
| + // Fetch non-system URLs.
|
| + if (tag == Dart_kImportTag) {
|
| + loader->m_pendingLibraries.add(url);
|
| + } else if (tag == Dart_kSourceTag) {
|
| + loader->m_pendingSource.add(url);
|
| + } else {
|
| + ASSERT_NOT_REACHED();
|
| + }
|
| + loader->fetchScriptResource(url);
|
| + }
|
| + return Dart_NewBoolean(true);
|
| +}
|
| +
|
| +class ScriptLoadedCallback : public ResourceClient {
|
| +public:
|
| + ScriptLoadedCallback(String url, PassRefPtr<DartAsyncLoader> loader, ResourcePtr<ScriptResource> scriptResource)
|
| + : m_url(url)
|
| + , m_loader(loader)
|
| + , m_scriptResource(scriptResource)
|
| + {
|
| + }
|
| +
|
| + virtual void notifyFinished(Resource* cachedResource)
|
| + {
|
| + ASSERT(cachedResource->type() == Resource::Script);
|
| + ASSERT(cachedResource == m_scriptResource.get());
|
| + ASSERT(WTF::isMainThread());
|
| +
|
| + if (cachedResource->errorOccurred()) {
|
| + m_loader->reportError(String("An error occurred loading file"), m_url);
|
| + } else if (cachedResource->wasCanceled()) {
|
| + // FIXME: shall we let VM know, so it can inform application some of its
|
| + // resources cannot be loaded?
|
| + m_loader->reportError(String("File request cancelled"), m_url);
|
| + } else {
|
| + ScriptSourceCode sourceCode(m_scriptResource.get());
|
| + // FIXME: Should we check for cached metadata?
|
| + // CachedMetadata* cachedMetadata = m_scriptResource->cachedMetadata(dartTypeID);
|
| +
|
| + // Use the original url associated with the Script so that
|
| + // redirects do not break the DartScriptLoader.
|
| + // FIXME: is this the correct behavior? This functionality is
|
| + // very convenient when you want the source file to act as if
|
| + // it was from the original location but that isn't always
|
| + // what the user expects.
|
| + m_loader->process(m_url, sourceCode.source(), 0);
|
| + }
|
| +
|
| + m_scriptResource->removeClient(this);
|
| + delete this;
|
| + }
|
| +
|
| +private:
|
| + String m_url;
|
| + RefPtr<DartAsyncLoader> m_loader;
|
| + ResourcePtr<ScriptResource> m_scriptResource;
|
| +};
|
| +
|
| +static String resolveUrl(String mainLibraryURL, const String& url)
|
| +{
|
| + if (!url.startsWith("package:") || url.startsWith("package://"))
|
| + return url;
|
| +
|
| + String packageRoot;
|
| + String packageUrl;
|
| + if (const char* packageRootOverride = getenv("DART_PACKAGE_ROOT")) {
|
| + // Resolve with respect to the override. Append a
|
| + // slash to ensure that resolution is against this
|
| + // path and not its parent.
|
| + packageRoot = String(packageRootOverride) + "/";
|
| + // Strip the 'package:' prefix.
|
| + packageUrl = url.substring(8);
|
| + } else {
|
| + // Resolve with respect to the entry point's URL. Note, the
|
| + // trailing file name in the entry point URL (e.g.,
|
| + // 'rootpath/mainapp.dart') is stripped by the KURL
|
| + // constructor below.
|
| + packageRoot = mainLibraryURL;
|
| + packageUrl = String("packages/") + url.substring(8);
|
| + }
|
| + return KURL(KURL(KURL(), packageRoot), packageUrl).string();
|
| +}
|
| +
|
| +void DartAsyncLoader::fetchScriptResource(const String& url)
|
| +{
|
| + // Request loading of script dependencies.
|
| + FetchRequest request(m_loadCallback->completeURL(resolveUrl(m_topUrl, url)),
|
| + FetchInitiatorTypeNames::document, "utf8");
|
| + // FIXME: what about charset for this script, maybe use charset of initial script tag?
|
| + ResourcePtr<ScriptResource> scriptResource = m_loadCallback->requestScript(request);
|
| + if (scriptResource)
|
| + scriptResource->addClient(new ScriptLoadedCallback(m_loadCallback->completeURL(url), this, scriptResource));
|
| + else
|
| + m_loadCallback->reportError(String("File request error"), url);
|
| +}
|
| +
|
| +}
|
|
|