Index: Source/WebCore/bindings/dart/DartUtilities.cpp |
diff --git a/Source/WebCore/bindings/dart/DartUtilities.cpp b/Source/WebCore/bindings/dart/DartUtilities.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..58718477bc8dea0c32036aac289f74a6b2a9ee6c |
--- /dev/null |
+++ b/Source/WebCore/bindings/dart/DartUtilities.cpp |
@@ -0,0 +1,429 @@ |
+// Copyright 2011, 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 "DartUtilities.h" |
+ |
+#include "DartEventListener.h" |
+#include "DartIsolateState.h" |
+#include "DartMessagePort.h" |
+#include "DartNode.h" |
+#include "DartScriptArguments.h" |
+#include "DartScriptValueSerializer.h" |
+#include "Document.h" |
+#include "Frame.h" |
+#include "ScriptCallStack.h" |
+#include "SerializedScriptValue.h" |
+ |
+#include <wtf/text/AtomicString.h> |
+#include <wtf/text/CString.h> |
+ |
+namespace WebCore { |
+ |
+const char* DartUtilities::domLibraryName = "dart:dom"; |
+ |
+PassRefPtr<StringImpl> DartUtilities::toStringImpl(Dart_Handle object, ConversionFlag flag, Dart_Handle& exception) |
+{ |
+ if (flag == ConvertNullToEmptyString && Dart_IsNull(object)) |
+ return 0; |
+ |
+ if (!Dart_IsString(object)) { |
+ exception = Dart_NewString("String expected"); |
+ return 0; |
+ } |
+ if (!Dart_IsString16(object)) { |
+ // FIXME: consider convertion to UTF16 in this case. |
+ exception = Dart_NewString("32-bit string met, cannot be used in DOM API"); |
+ return 0; |
+ } |
+ |
+ // Note: hopefully we should never overflow length as the string would be just too long to fit |
+ // into memory. |
+ intptr_t length = 0; |
+ Dart_StringLength(object, &length); |
+ UChar* buffer; |
+ // FIXME: check if string is externalized, and reuse that, if possible. |
+ RefPtr<StringImpl> result = StringImpl::createUninitialized(length, buffer); |
+ Dart_StringGet16(object, buffer, &length); |
+ return result.release(); |
+} |
+ |
+static void stringFinalizer(void* peer) { |
+ StringImpl* stringImpl = reinterpret_cast<StringImpl*>(peer); |
+ stringImpl->deref(); |
+} |
+ |
+static Dart_Handle stringImplToDartString(StringImpl* stringImpl) |
+{ |
+ if (!stringImpl) |
+ return Dart_NewString8(0, 0); |
+ |
+ // FIXME: maybe it makes sense only externalize strings longer than certain threshold, such as 5 symbols. |
+ stringImpl->ref(); |
+ return Dart_NewExternalString16(stringImpl->characters(), stringImpl->length(), |
+ stringImpl, stringFinalizer); |
+} |
+ |
+Dart_Handle DartUtilities::stringToDartString(const String& str) |
+{ |
+ return stringImplToDartString(str.impl()); |
+} |
+ |
+Dart_Handle DartUtilities::stringToDartString(const AtomicString& str) |
+{ |
+ return stringImplToDartString(str.impl()); |
+} |
+ |
+template <typename Trait> |
+typename Trait::nativeType convert(Dart_Handle object, Dart_Handle& exception) |
+{ |
+ typename Trait::nativeType value; |
+ return !Dart_IsError(Trait::convert(object, &value)) ? value : typename Trait::nativeType(); |
+} |
+ |
+struct IntegerTrait { |
+ typedef int64_t nativeType; |
+ static Dart_Handle convert(Dart_Handle object, int64_t* value) |
+ { |
+ return Dart_IntegerValue(object, value); |
+ // FIXME: support bigints. |
+ } |
+}; |
+ |
+int64_t DartUtilities::toInteger(Dart_Handle object, Dart_Handle& exception) |
+{ |
+ return convert<IntegerTrait>(object, exception); |
+} |
+ |
+int64_t DartUtilities::toInteger(Dart_Handle object) |
+{ |
+ Dart_Handle exception = 0; |
+ int64_t value = DartUtilities::toInteger(object, exception); |
+ ASSERT(!exception); |
+ return value; |
+} |
+ |
+struct DoubleTrait { |
+ typedef double nativeType; |
+ static Dart_Handle convert(Dart_Handle object, double* value) |
+ { |
+ if (!Dart_IsNumber(object)) |
+ return Dart_Error("the object !is Number"); |
+ |
+ object = Dart_InvokeDynamic(object, Dart_NewString("toDouble"), 0, 0); |
+ if (Dart_IsError(object)) |
+ return object; |
+ |
+ return Dart_DoubleValue(object, value); |
+ } |
+}; |
+ |
+double DartUtilities::toDouble(Dart_Handle object, Dart_Handle& exception) |
+{ |
+ return convert<DoubleTrait>(object, exception); |
+} |
+ |
+double DartUtilities::toDouble(Dart_Handle object) |
+{ |
+ Dart_Handle exception = 0; |
+ double value = DartUtilities::toDouble(object, exception); |
+ ASSERT(!exception); |
+ return value; |
+} |
+ |
+struct BoolTrait { |
+ typedef bool nativeType; |
+ static Dart_Handle convert(Dart_Handle object, bool* value) { return Dart_BooleanValue(object, value); } |
+}; |
+ |
+bool DartUtilities::toBool(Dart_Handle object, Dart_Handle& exception) |
+{ |
+ return convert<BoolTrait>(object, exception); |
+} |
+ |
+bool DartUtilities::toBool(Dart_Handle object) |
+{ |
+ Dart_Handle exception = 0; |
+ bool value = DartUtilities::toBool(object, exception); |
+ ASSERT(!exception); |
+ return value; |
+} |
+ |
+PassRefPtr<EventListener> DartUtilities::toEventListener(Dart_Handle object, Dart_Handle& exception) |
+{ |
+ if (Dart_IsNull(object)) { |
+ exception = Dart_NewString("Null passed where Dart closure is expected"); |
+ return 0; |
+ } |
+ |
+ if (!Dart_IsClosure(object)) { |
+ exception = Dart_NewString("Not a Dart closure passed"); |
+ return 0; |
+ } |
+ |
+ return DartEventListener::createOrFetch(object); |
+} |
+ |
+PassRefPtr<SerializedScriptValue> DartUtilities::toSerializedScriptValue(Dart_Handle value, Dart_Handle& exception) |
+{ |
+ DartScriptValueSerializer serializer(value); |
+ RefPtr<SerializedScriptValue> result = SerializedScriptValue::create(&serializer); |
+ exception = serializer.exception(); |
+ return result.release(); |
+} |
+ |
+PassRefPtr<EventTarget> DartUtilities::toEventTarget(Dart_Handle object, Dart_Handle& exception) |
+{ |
+ // FIXME: currently it's too risky to remove, but when Optional=CallWithDefaultValue is |
+ // implemented, we should give it a try and unify with the rest of conversion. |
+ if (Dart_IsNull(object)) |
+ return 0; |
+ |
+ return DartNode::toNative(object, exception); |
+} |
+ |
+// FIXME: this function requires better testing. Currently blocking as new MessageChannel hasn't been implemented yet. |
+void DartUtilities::toMessagePortArray(Dart_Handle value, MessagePortArray& portArray, Dart_Handle& exception) |
+{ |
+ Dart_Handle dom = Dart_LookupLibrary(Dart_NewString(DartUtilities::domLibraryName)); |
+ ASSERT(!Dart_IsError(dom)); |
+ |
+ Dart_Handle asList = Dart_InvokeStatic(dom, Dart_NewString("Utils"), Dart_NewString("convertToList"), 1, &value); |
+ if (Dart_IsError(asList)) { |
+ DartUtilities::reportProblem(DartUtilities::scriptExecutionContext(), asList); |
+ exception = DartDOMWrapper::exceptionCodeToDartException(INVALID_STATE_ERR); |
+ return; |
+ } |
+ ASSERT(Dart_IsList(asList)); |
+ |
+ intptr_t length = 0; |
+ Dart_ListLength(asList, &length); |
+ portArray.resize(length); |
+ for (int i = 0; i < length; i++) { |
+ Dart_Handle element = Dart_ListGetAt(asList, i); |
+ if (Dart_IsError(element)) { |
+ exception = DartDOMWrapper::exceptionCodeToDartException(INVALID_STATE_ERR); |
+ return; |
+ } |
+ |
+ MessagePort* messagePort = DartMessagePort::toNative(element, exception).get(); |
+ if (exception) { |
+ exception = DartDOMWrapper::exceptionCodeToDartException(INVALID_STATE_ERR); |
+ return; |
+ } |
+ |
+ ASSERT(messagePort); |
+ portArray[i] = messagePort; |
+ } |
+} |
+ |
+class DartDOMData { |
+public: |
+ DartDOMData() |
+ : m_scriptExecutionContext(0) |
+ , m_domWindow(0) |
+ , m_recursion(0) |
+ { |
+ } |
+ |
+ DartDOMData(ScriptExecutionContext* context) |
+ : m_scriptExecutionContext(context) |
+ , m_recursion(0) |
+ { |
+ ASSERT(context); |
+ ASSERT(context->isDocument()); // WorkerContext is not supported yet. |
+ Document* document = static_cast<Document*>(context); |
+ m_domWindow = document->domWindow(); |
+ } |
+ |
+ ScriptExecutionContext* scriptExecutionContext() { return m_scriptExecutionContext; } |
+ DOMWindow* domWindow() { return m_domWindow; } |
+ DartDOMMap* domMap() { return &m_domMap; } |
+ int* recursion() { return &m_recursion; } |
+ |
+private: |
+ ScriptExecutionContext* m_scriptExecutionContext; |
+ DOMWindow* m_domWindow; |
+ DartDOMMap m_domMap; |
+ int m_recursion; |
+}; |
+ |
+typedef HashMap<Dart_Isolate, DartDOMData*> IsolateToDartDOMDataMap; |
+ |
+static IsolateToDartDOMDataMap& isolateToDartDOMDataMap() |
+{ |
+ DEFINE_STATIC_LOCAL(IsolateToDartDOMDataMap, map, ()); |
+ return map; |
+} |
+ |
+static DartDOMData* domDataForIsolate(Dart_Isolate isolate) |
+{ |
+ IsolateToDartDOMDataMap::iterator it = isolateToDartDOMDataMap().find(isolate); |
+ ASSERT(it != isolateToDartDOMDataMap().end()); |
+ return it->second; |
+} |
+ |
+static DartDOMData* currentDOMData() |
+{ |
+ return domDataForIsolate(DartIsolateState::current()); |
+} |
+ |
+void DartUtilities::registerIsolateContext(Dart_Isolate isolate, ScriptExecutionContext* context) |
+{ |
+ ASSERT(!isolateToDartDOMDataMap().contains(isolate)); |
+ isolateToDartDOMDataMap().set(isolate, new DartDOMData(context)); |
+} |
+ |
+ScriptExecutionContext* DartUtilities::isolateContext(Dart_Isolate isolate) |
+{ |
+ return domDataForIsolate(isolate)->scriptExecutionContext(); |
+} |
+ |
+void DartUtilities::unregisterIsolateContext(Dart_Isolate isolate) |
+{ |
+ IsolateToDartDOMDataMap::iterator it = isolateToDartDOMDataMap().find(isolate); |
+ ASSERT(it != isolateToDartDOMDataMap().end()); |
+ delete it->second; |
+ isolateToDartDOMDataMap().remove(it); |
+} |
+ |
+bool DartUtilities::isFullDomIsolate(Dart_Isolate isolate) |
+{ |
+ return isolateToDartDOMDataMap().contains(isolate); |
+} |
+ |
+DOMWindow* DartUtilities::domWindowForIsolate(Dart_Isolate isolate) |
+{ |
+ return domDataForIsolate(isolate)->domWindow(); |
+} |
+ |
+DOMWindow* DartUtilities::domWindowForCurrentIsolate() |
+{ |
+ return currentDOMData()->domWindow(); |
+} |
+ |
+Dart_Handle DartUtilities::domLibraryForCurrentIsolate() |
+{ |
+ // FIXME: Cache this on the isolate. |
+ Dart_Handle library = Dart_LookupLibrary(Dart_NewString(domLibraryName)); |
+ ASSERT(!Dart_IsError(library)); |
+ return library; |
+} |
+ |
+DartDOMMap* DartUtilities::domMapForIsolate(Dart_Isolate isolate) |
+{ |
+ return domDataForIsolate(isolate)->domMap(); |
+} |
+ |
+DartDOMMap* DartUtilities::domMapForCurrentIsolate() |
+{ |
+ return currentDOMData()->domMap(); |
+} |
+ |
+int* DartUtilities::recursionForIsolate(Dart_Isolate isolate) |
+{ |
+ return domDataForIsolate(isolate)->recursion(); |
+} |
+ |
+int* DartUtilities::recursionForCurrentIsolate() |
+{ |
+ return currentDOMData()->recursion(); |
+} |
+ |
+ScriptExecutionContext* DartUtilities::scriptExecutionContext() |
+{ |
+ return currentDOMData()->scriptExecutionContext(); |
+} |
+ |
+bool DartUtilities::processingUserGesture() |
+{ |
+ // FIXME: implement this. |
+ return false; |
+} |
+ |
+PassRefPtr<ScriptArguments> DartUtilities::createScriptArguments(Dart_Handle argument) |
+{ |
+ return DartScriptArguments::create(argument, DartIsolateState::current()); |
+} |
+ |
+PassRefPtr<ScriptCallStack> DartUtilities::createScriptCallStack(size_t maxStackSize) |
+{ |
+ // FIXME: wrap current dart call stack as ScriptCallStack. |
+ Vector<ScriptCallFrame> wrappedCallFrames; |
+ wrappedCallFrames.append(ScriptCallFrame("undefined", "undefined", 0)); |
+ return ScriptCallStack::create(wrappedCallFrames); |
+} |
+ |
+void DartUtilities::reportProblem(ScriptExecutionContext* context, Dart_Handle result) |
+{ |
+ ASSERT(Dart_IsError(result)); |
+ |
+ const String internalErrorPrefix("Internal error: "); |
+ |
+ String errorMessage; |
+ // FIXME: source file info. |
+ String sourceFile = "FIXME"; |
+ // FIXME: line number info. |
+ int lineNumber = 0; |
+ // FIXME: call stack info. |
+ RefPtr<ScriptCallStack> callStack; |
+ |
+ if (!Dart_ErrorHasException(result)) |
+ errorMessage = internalErrorPrefix + Dart_GetError(result); |
+ else { |
+ // Print the exception. |
+ Dart_Handle exception = Dart_ErrorGetException(result); |
+ ASSERT(!Dart_IsError(exception)); |
+ |
+ exception = Dart_ToString(exception); |
+ if (Dart_IsError(exception)) |
+ errorMessage = String("Error converting exception to a string: ") + Dart_GetError(exception); |
+ else |
+ errorMessage = String("Exception: ") + DartUtilities::dartStringToString(exception); |
+ |
+ // FIXME: Fill in the callStack, sourceFile, and lineNumber |
+ // and remove the below once the Dart APIs to iterate over the |
+ // trace are available. |
+ |
+ // Print the stack trace. |
+ Dart_Handle stacktrace = Dart_ErrorGetStacktrace(result); |
+ ASSERT(!Dart_IsError(stacktrace)); |
+ |
+ stacktrace = Dart_ToString(stacktrace); |
+ if (Dart_IsError(stacktrace)) |
+ errorMessage += String("\nError converting stack trace to a string: ") + Dart_GetError(stacktrace); |
+ else |
+ errorMessage += String("\nStack Trace: ") + DartUtilities::dartStringToString(stacktrace); |
+ } |
+ |
+ if (context && context->isDocument()) |
+ static_cast<Document*>(context)->reportException(errorMessage, lineNumber, sourceFile, callStack); |
+} |
+ |
+} |