| Index: Source/WebCore/bindings/dart/DartController.cpp
|
| diff --git a/Source/WebCore/bindings/dart/DartController.cpp b/Source/WebCore/bindings/dart/DartController.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..51ac0767c5522938f76c45cc911540c25f46cdea
|
| --- /dev/null
|
| +++ b/Source/WebCore/bindings/dart/DartController.cpp
|
| @@ -0,0 +1,307 @@
|
| +// 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 "DartController.h"
|
| +
|
| +#include "DOMWindow.h"
|
| +#include "DartApplicationLoader.h"
|
| +#include "DartBuiltinLibrarySource.h"
|
| +#include "DartClassInfo.h"
|
| +#include "DartDOMLibrarySource.h"
|
| +#include "DartDOMWindow.h"
|
| +#include "DartDOMWrapper.h"
|
| +#include "DartFlags.h"
|
| +#include "DartIsolateState.h"
|
| +#include "DartUtilities.h"
|
| +#include "Document.h"
|
| +#include "Frame.h"
|
| +#include "IDBPendingTransactionMonitor.h"
|
| +#include "JavaScriptController.h"
|
| +#include "Page.h"
|
| +#include "PageGroup.h"
|
| +#include "ScriptExecutionContext.h"
|
| +#include "Settings.h"
|
| +#include "StorageNamespace.h"
|
| +
|
| +#include "npruntime_impl.h"
|
| +#include <bindings/npruntime.h>
|
| +
|
| +namespace WebCore {
|
| +
|
| +static void initDOMIsolate()
|
| +{
|
| + DartApiScope dartApiScope;
|
| +
|
| + // Create the dom library.
|
| + Dart_Handle dom = Dart_LoadLibrary(Dart_NewString(DartUtilities::domLibraryName), Dart_NewString("#library(\"Dom\");"));
|
| + ASSERT(!Dart_IsError(dom));
|
| + Dart_LibraryImportLibrary(dom, Dart_LookupLibrary(Dart_NewString("dart:coreimpl")));
|
| + // FIXME: add return value checks.
|
| + Dart_LoadSource(dom, Dart_NewString("DOMExtensions"), Dart_NewString(dartDOMLibrarySource));
|
| + Dart_CreateNativeWrapperClass(dom, Dart_NewString("DOMWrapperBase"), DartDOMWrapper::wrapperNativeFieldCount());
|
| +
|
| + // Inject builtin library to forward core functionality to dom.
|
| + // FIXME: We need to provide something for non-DOM isolates as well.
|
| + Dart_Handle core = Dart_LookupLibrary(Dart_NewString("dart:core"));
|
| + Dart_LoadSource(core, Dart_NewString("dart:builtin"), Dart_NewString(dartBuiltinLibrarySource));
|
| + Dart_LibraryImportLibrary(core, dom);
|
| +
|
| + DartClassInfo::registerClasses(dom);
|
| +}
|
| +
|
| +DartPerScriptState::DartPerScriptState(Document* document, NPObject* layoutTestController)
|
| + : m_dartApplicationLoader(adoptRef(new DartApplicationLoader(document, layoutTestController)))
|
| + , m_isolate(DartIsolateState::create(document, m_dartApplicationLoader.get()))
|
| +{
|
| + initDOMIsolate();
|
| + isolateToDartApplicationLoaderMap().set(m_isolate, m_dartApplicationLoader.get());
|
| + // DartIsolateState::create pushes newly create isolate, undo it.
|
| + DartIsolateState::pop();
|
| +}
|
| +
|
| +DartPerScriptState::~DartPerScriptState()
|
| +{
|
| + *DartUtilities::recursionForIsolate(m_isolate) = 0;
|
| + isolateToDartApplicationLoaderMap().remove(m_isolate);
|
| + DartIsolateState::shutdown(m_isolate);
|
| +}
|
| +
|
| +DartController::DartController(Frame* frame)
|
| + : m_frame(frame)
|
| + , m_states()
|
| + , m_layoutTestController(0)
|
| +{
|
| + // The DartController's constructor must be called in the Frame's
|
| + // constructor, so it can properly maintain the unit of related
|
| + // browsing contexts.
|
| +
|
| + // The DartController must be created after the frame's loader and
|
| + // tree nodes are initialized.
|
| + ASSERT(frame->loader());
|
| + ASSERT(frame->tree());
|
| +}
|
| +
|
| +void DartController::clearWindowShell()
|
| +{
|
| + m_states.clear();
|
| +}
|
| +
|
| +class PostMessageTask : public ScriptExecutionContext::Task {
|
| +public:
|
| + PostMessageTask(Dart_Isolate destinationIsolate, Dart_Port destinationPort, Dart_Port replyPort, Dart_Message message)
|
| + : m_destinationIsolate(destinationIsolate)
|
| + , m_destinationPort(destinationPort)
|
| + , m_replyPort(replyPort)
|
| + , m_message(message) { }
|
| +
|
| + ~PostMessageTask()
|
| + {
|
| + free(m_message);
|
| + }
|
| +
|
| + virtual void performTask(ScriptExecutionContext* context)
|
| + {
|
| + // FIXME: one shouldn't trust isFullDomIsolate as another
|
| + // isolate with the same address might be allocated. Apparently better
|
| + // way would be to maintain a way to tell all the tasks that they are
|
| + // cancelled from now on. For example, we may maintain a list of all
|
| + // pending tasks and iterate over it.
|
| + // destinationIsolate might have been shut down before.
|
| + if (!DartUtilities::isFullDomIsolate(m_destinationIsolate))
|
| + return;
|
| + DartIsolateState::Scope scope(m_destinationIsolate);
|
| + DartApiScope apiScope;
|
| + Dart_Handle result = Dart_HandleMessage(m_destinationPort, m_replyPort, m_message);
|
| + if (Dart_IsError(result))
|
| + DartUtilities::reportProblem(context, result);
|
| + }
|
| +
|
| +private:
|
| + Dart_Isolate m_destinationIsolate;
|
| + Dart_Port m_destinationPort;
|
| + Dart_Port m_replyPort;
|
| + Dart_Message m_message;
|
| +};
|
| +
|
| +static bool postMessageCallback(Dart_Isolate destinationIsolate, Dart_Port destinationPort, Dart_Port replyPort, Dart_Message message)
|
| +{
|
| + ASSERT(DartUtilities::isFullDomIsolate(destinationIsolate));
|
| + ScriptExecutionContext* destinationContext = DartUtilities::isolateContext(destinationIsolate);
|
| + destinationContext->postTask(adoptPtr(new PostMessageTask(destinationIsolate, destinationPort, replyPort, message)));
|
| + return true;
|
| +}
|
| +
|
| +static void closePortCallback(Dart_Isolate, Dart_Port)
|
| +{
|
| +}
|
| +
|
| +void DartController::setupDOMEnabledIsolate(ScriptExecutionContext* context)
|
| +{
|
| + ASSERT(context);
|
| + Dart_SetMessageCallbacks(&postMessageCallback, &closePortCallback);
|
| + DartUtilities::registerIsolateContext(Dart_CurrentIsolate(), context);
|
| +}
|
| +
|
| +bool DartController::initializeIsolateCallback(void* data, char** errorMsg)
|
| +{
|
| + Dart_Isolate isolate = Dart_CreateIsolate(0, data, errorMsg);
|
| + if (!isolate)
|
| + return false;
|
| +
|
| + DartApiScope dartApiScope;
|
| +
|
| + // It's safe to reinitialize DOM in all isolates: unless Dart isolate is
|
| + // registered with DartUtilities::registerIsolatecContext, it's DOM functionality
|
| + // will be disabled: we won't be able to resolve top level accessors.
|
| + initDOMIsolate();
|
| +
|
| + DartApplicationLoader* dartApplicationLoader = reinterpret_cast<DartApplicationLoader*>(data);
|
| + // FIXME: when DartVM has shutdown callback, we'll be able to deref it.
|
| + dartApplicationLoader->ref();
|
| +
|
| + ASSERT(!dartApplicationLoader->isLoadingMainIsolate());
|
| + dartApplicationLoader->reinjectSources();
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void DartController::initVMIfNeeded()
|
| +{
|
| + static bool hasBeenInitialized = false;
|
| + if (hasBeenInitialized)
|
| + return;
|
| +
|
| + int argc = DartFlags::count();
|
| + const char** argv = const_cast<const char**>(DartFlags::flags());
|
| + Dart_SetVMFlags(argc, argv);
|
| + Dart_Initialize(&initializeIsolateCallback);
|
| + hasBeenInitialized = true;
|
| +}
|
| +
|
| +bool DartController::isScriptTypeSupported(const String& mimeType)
|
| +{
|
| + DEFINE_STATIC_LOCAL(HashSet<String>, types, ());
|
| + if (types.isEmpty()) {
|
| + types.add("application/dart");
|
| + types.add("application/dart-app");
|
| + types.add("application/dart-script");
|
| + }
|
| + return !mimeType.isEmpty() && types.contains(mimeType);
|
| +}
|
| +
|
| +void DartController::evaluate(const ScriptSourceCode& sourceCode)
|
| +{
|
| + if (!m_frame->page()->settings()->isDartEnabled())
|
| + return;
|
| +
|
| + initVMIfNeeded();
|
| +
|
| + // FIXME: it may make sense to ensure that we'll never call evaluate more than once for the same script tag.
|
| + DartPerScriptState* state = new DartPerScriptState(frame()->document(), m_layoutTestController);
|
| + ASSERT(state->isolate());
|
| + m_states.append(adoptPtr(state));
|
| +
|
| + DartIsolateState::Scope scope(state->isolate());
|
| + state->dartApplicationLoader()->load(sourceCode.url(), sourceCode.source());
|
| +}
|
| +
|
| +void DartController::bindToWindowObject(Frame*, const String& key, NPObject* object)
|
| +{
|
| + // FIXME: production code should not know anything about layoutTestController.
|
| + if (key != "layoutTestController")
|
| + return;
|
| +
|
| + // FIXME: proper management of lifetime.
|
| + ASSERT(m_states.isEmpty());
|
| + m_layoutTestController = object;
|
| +}
|
| +
|
| +Dart_Handle DartController::callFunction(Dart_Handle function, int argc, Dart_Handle* argv)
|
| +{
|
| + // FIXME: Introduce Dart variant of V8GCController::checkMemoryUsage();
|
| + const int kMaxRecursionDepth = 22;
|
| +
|
| + int* recursion = DartUtilities::recursionForCurrentIsolate();
|
| +
|
| + if (*recursion >= kMaxRecursionDepth)
|
| + return Dart_Error("Maximum call stack size exceeded");
|
| +
|
| + // FIXME: implement InspectorInstrumentationCookie stuff a la v8.
|
| + (*recursion)++;
|
| + Dart_Handle result = Dart_InvokeClosure(function, argc, argv);
|
| + (*recursion)--;
|
| +
|
| + // Release the storage mutex if applicable.
|
| + didLeaveScriptContext(*recursion);
|
| +
|
| + // Handle fatal error in Dart VM a la v8.
|
| +
|
| + return result;
|
| +}
|
| +
|
| +void DartController::didLeaveScriptContext(int recursion)
|
| +{
|
| + // FIXME: common to v8, should be factored out.
|
| + Page* page = m_frame->page();
|
| + if (!page)
|
| + return;
|
| +#if ENABLE(INDEXED_DATABASE)
|
| + // If we've just left a script context and indexed database has been
|
| + // instantiated, we must let its transaction coordinator know so it can terminate
|
| + // any not-yet-started transactions.
|
| + IDBPendingTransactionMonitor::abortPendingTransactions();
|
| +#endif // ENABLE(INDEXED_DATABASE)
|
| + // If we've just left a top level script context and local storage has been
|
| + // instantiated, we must ensure that any storage locks have been freed.
|
| + // Per http://dev.w3.org/html5/spec/Overview.html#storage-mutex
|
| + if (recursion)
|
| + return;
|
| + if (page->group().hasLocalStorage())
|
| + page->group().localStorage()->unlock();
|
| +}
|
| +
|
| +DartController* DartController::retrieve(Frame* frame)
|
| +{
|
| + if (!frame)
|
| + return 0;
|
| + // FIXME: check if can execute Dart scripts.
|
| + if (!frame->script()->javaScript()->canExecuteScripts(NotAboutToExecuteScript))
|
| + return 0;
|
| + return frame->script()->dart();
|
| +}
|
| +
|
| +DartController* DartController::retrieve(ScriptExecutionContext* context)
|
| +{
|
| + if (!context || !context->isDocument())
|
| + return 0;
|
| + return retrieve(static_cast<Document*>(context)->frame());
|
| +}
|
| +
|
| +}
|
|
|