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()); |
+} |
+ |
+} |