summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-20 21:28:10 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-20 21:28:10 +0000
commitb1cf337a2722a4c24802b78258ea96e8e8d00276 (patch)
treec473a077154b97d23c781736aece0b1f847803af
parent25c171129de0c3da8fa5e45be90335f07c06a20a (diff)
downloadchromium_src-b1cf337a2722a4c24802b78258ea96e8e8d00276.zip
chromium_src-b1cf337a2722a4c24802b78258ea96e8e8d00276.tar.gz
chromium_src-b1cf337a2722a4c24802b78258ea96e8e8d00276.tar.bz2
Add V8ValueConverter utility to convert between v8::Value and
base::Value. BUG= TEST= Review URL: http://codereview.chromium.org/6882054 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@82358 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/extension_messages_browsertest.cc9
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/renderer/extensions/chrome_app_bindings.cc21
-rw-r--r--chrome/renderer/extensions/event_bindings.cc20
-rw-r--r--chrome/renderer/extensions/event_bindings.h5
-rw-r--r--chrome/renderer/extensions/extension_dispatcher.cc2
-rw-r--r--chrome/renderer/extensions/extension_helper.cc4
-rw-r--r--chrome/renderer/extensions/renderer_extension_bindings.cc63
-rw-r--r--chrome/renderer/extensions/renderer_extension_bindings.h10
-rw-r--r--content/content_renderer.gypi2
-rw-r--r--content/renderer/render_view.cc40
-rw-r--r--content/renderer/v8_value_converter.cc156
-rw-r--r--content/renderer/v8_value_converter.h56
-rw-r--r--content/renderer/v8_value_converter_browsertest.cc84
14 files changed, 341 insertions, 132 deletions
diff --git a/chrome/browser/extensions/extension_messages_browsertest.cc b/chrome/browser/extensions/extension_messages_browsertest.cc
index c7a9b76..f4f7649 100644
--- a/chrome/browser/extensions/extension_messages_browsertest.cc
+++ b/chrome/browser/extensions/extension_messages_browsertest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,7 +7,6 @@
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/render_messages.h"
#include "chrome/renderer/extensions/event_bindings.h"
-#include "chrome/renderer/extensions/renderer_extension_bindings.h"
#include "chrome/test/render_view_test.h"
#include "content/common/view_messages.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,14 +22,14 @@ static void DispatchOnConnect(int source_port_id, const std::string& name,
// to itself".
args.Set(3, Value::CreateStringValue(EventBindings::kTestingExtensionId));
args.Set(4, Value::CreateStringValue(EventBindings::kTestingExtensionId));
- RendererExtensionBindings::Invoke(
+ EventBindings::CallFunction(
"", ExtensionMessageService::kDispatchOnConnect, args, NULL, GURL());
}
static void DispatchOnDisconnect(int source_port_id) {
ListValue args;
args.Set(0, Value::CreateIntegerValue(source_port_id));
- RendererExtensionBindings::Invoke(
+ EventBindings::CallFunction(
"", ExtensionMessageService::kDispatchOnDisconnect, args, NULL, GURL());
}
@@ -38,7 +37,7 @@ static void DispatchOnMessage(const std::string& message, int source_port_id) {
ListValue args;
args.Set(0, Value::CreateStringValue(message));
args.Set(1, Value::CreateIntegerValue(source_port_id));
- RendererExtensionBindings::Invoke(
+ EventBindings::CallFunction(
"", ExtensionMessageService::kDispatchOnMessage, args, NULL, GURL());
}
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index d62ee68..395aaf3 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2407,6 +2407,7 @@
'../content/renderer/render_view_browsertest_mac.mm',
'../content/renderer/render_widget_browsertest.cc',
'../content/renderer/render_widget_browsertest.h',
+ '../content/renderer/v8_value_converter_browsertest.cc',
],
'conditions': [
['chromeos==0', {
diff --git a/chrome/renderer/extensions/chrome_app_bindings.cc b/chrome/renderer/extensions/chrome_app_bindings.cc
index aafa672..5c760dd 100644
--- a/chrome/renderer/extensions/chrome_app_bindings.cc
+++ b/chrome/renderer/extensions/chrome_app_bindings.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,6 +16,7 @@
#include "chrome/renderer/extensions/extension_dispatcher.h"
#include "chrome/renderer/extensions/extension_helper.h"
#include "content/renderer/render_view.h"
+#include "content/renderer/v8_value_converter.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "v8/include/v8.h"
@@ -71,14 +72,8 @@ class ChromeAppExtensionWrapper : public v8::Extension {
" native function GetDetailsForFrame();"
" this.__defineGetter__('isInstalled', GetIsInstalled);"
" this.install = Install;"
- " this.getDetails = function() {"
- " var json = GetDetails();"
- " return json == null ? null : JSON.parse(json);"
- " };"
- " this.getDetailsForFrame = function(frame) {"
- " var json = GetDetailsForFrame(frame);"
- " return json == null ? null : JSON.parse(json);"
- " };"
+ " this.getDetails = GetDetails;"
+ " this.getDetailsForFrame = GetDetailsForFrame;"
" };"
"}") {
extension_dispatcher_ = extension_dispatcher;
@@ -169,14 +164,12 @@ class ChromeAppExtensionWrapper : public v8::Extension {
if (!extension)
return v8::Null();
- std::string manifest_json;
- const bool kPrettyPrint = false;
scoped_ptr<DictionaryValue> manifest_copy(
extension->manifest_value()->DeepCopy());
manifest_copy->SetString("id", extension->id());
- base::JSONWriter::Write(manifest_copy.get(), kPrettyPrint, &manifest_json);
-
- return v8::String::New(manifest_json.c_str(), manifest_json.size());
+ V8ValueConverter converter;
+ return converter.ToV8Value(manifest_copy.get(),
+ frame->mainWorldScriptContext());
}
static ExtensionDispatcher* extension_dispatcher_;
diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc
index 921a82e..01d0f55 100644
--- a/chrome/renderer/extensions/event_bindings.cc
+++ b/chrome/renderer/extensions/event_bindings.cc
@@ -4,6 +4,8 @@
#include "chrome/renderer/extensions/event_bindings.h"
+#include <vector>
+
#include "base/basictypes.h"
#include "base/lazy_instance.h"
#include "base/message_loop.h"
@@ -17,6 +19,7 @@
#include "chrome/renderer/extensions/js_only_v8_extensions.h"
#include "content/renderer/render_thread.h"
#include "content/renderer/render_view.h"
+#include "content/renderer/v8_value_converter.h"
#include "googleurl/src/gurl.h"
#include "grit/renderer_resources.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h"
@@ -382,14 +385,17 @@ void EventBindings::HandleContextDestroyed(WebFrame* frame) {
// static
void EventBindings::CallFunction(const std::string& extension_id,
const std::string& function_name,
- int argc, v8::Handle<v8::Value>* argv,
+ const ListValue& arguments,
RenderView* render_view,
const GURL& event_url) {
+ v8::HandleScope handle_scope;
+
// We copy the context list, because calling into javascript may modify it
// out from under us. We also guard against deleted contexts by checking if
// they have been cleared first.
ContextList contexts = GetContexts();
+ V8ValueConverter converter;
for (ContextList::iterator it = contexts.begin();
it != contexts.end(); ++it) {
if (render_view && render_view != (*it)->render_view)
@@ -404,8 +410,16 @@ void EventBindings::CallFunction(const std::string& extension_id,
if (!HasSufficientPermissions(it->get(), event_url))
continue;
- v8::Handle<v8::Value> retval = CallFunctionInContext((*it)->context,
- function_name, argc, argv);
+ v8::Local<v8::Context> context(*((*it)->context));
+ std::vector<v8::Handle<v8::Value> > v8_arguments;
+ for (size_t i = 0; i < arguments.GetSize(); ++i) {
+ Value* item = NULL;
+ CHECK(arguments.Get(i, &item));
+ v8_arguments.push_back(converter.ToV8Value(item, context));
+ }
+
+ v8::Handle<v8::Value> retval = CallFunctionInContext(
+ context, function_name, v8_arguments.size(), &v8_arguments[0]);
// In debug, the js will validate the event parameters and return a
// string if a validation error has occured.
// TODO(rafaelw): Consider only doing this check if function_name ==
diff --git a/chrome/renderer/extensions/event_bindings.h b/chrome/renderer/extensions/event_bindings.h
index 893e3a6..59d26e6 100644
--- a/chrome/renderer/extensions/event_bindings.h
+++ b/chrome/renderer/extensions/event_bindings.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,6 +12,7 @@
class ExtensionDispatcher;
class GURL;
+class ListValue;
class RenderThreadBase;
class RenderView;
@@ -45,7 +46,7 @@ class EventBindings {
// v8::Undefined(). A DCHECK is setup to break if it is otherwise.
static void CallFunction(const std::string& extension_id,
const std::string& function_name,
- int argc, v8::Handle<v8::Value>* argv,
+ const ListValue& arguments,
RenderView* render_view,
const GURL& event_url);
};
diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc
index 2d789ac..c1f2a6e 100644
--- a/chrome/renderer/extensions/extension_dispatcher.cc
+++ b/chrome/renderer/extensions/extension_dispatcher.cc
@@ -124,7 +124,7 @@ void ExtensionDispatcher::OnMessageInvoke(const std::string& extension_id,
const std::string& function_name,
const ListValue& args,
const GURL& event_url) {
- RendererExtensionBindings::Invoke(
+ EventBindings::CallFunction(
extension_id, function_name, args, NULL, event_url);
// Reset the idle handler each time there's any activity like event or message
diff --git a/chrome/renderer/extensions/extension_helper.cc b/chrome/renderer/extensions/extension_helper.cc
index 691e7cb..bbe638b 100644
--- a/chrome/renderer/extensions/extension_helper.cc
+++ b/chrome/renderer/extensions/extension_helper.cc
@@ -12,9 +12,9 @@
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
+#include "chrome/renderer/extensions/event_bindings.h"
#include "chrome/renderer/extensions/extension_dispatcher.h"
#include "chrome/renderer/extensions/extension_process_bindings.h"
-#include "chrome/renderer/extensions/renderer_extension_bindings.h"
#include "chrome/renderer/extensions/user_script_idle_scheduler.h"
#include "chrome/renderer/extensions/user_script_slave.h"
#include "content/common/json_value_serializer.h"
@@ -182,7 +182,7 @@ void ExtensionHelper::OnExtensionMessageInvoke(const std::string& extension_id,
const std::string& function_name,
const ListValue& args,
const GURL& event_url) {
- RendererExtensionBindings::Invoke(
+ EventBindings::CallFunction(
extension_id, function_name, args, render_view(), event_url);
}
diff --git a/chrome/renderer/extensions/renderer_extension_bindings.cc b/chrome/renderer/extensions/renderer_extension_bindings.cc
index d9507b5..3d9784a 100644
--- a/chrome/renderer/extensions/renderer_extension_bindings.cc
+++ b/chrome/renderer/extensions/renderer_extension_bindings.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,6 @@
#include "base/basictypes.h"
#include "base/lazy_instance.h"
-#include "base/values.h"
#include "chrome/common/extensions/extension_message_bundle.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/url_constants.h"
@@ -245,51 +244,6 @@ class ExtensionImpl : public ExtensionBase {
}
};
-// Convert a ListValue to a vector of V8 values.
-static std::vector< v8::Handle<v8::Value> > ListValueToV8(
- const ListValue& value) {
- std::vector< v8::Handle<v8::Value> > v8_values;
-
- for (size_t i = 0; i < value.GetSize(); ++i) {
- Value* elem = NULL;
- value.Get(i, &elem);
- switch (elem->GetType()) {
- case Value::TYPE_NULL:
- v8_values.push_back(v8::Null());
- break;
- case Value::TYPE_BOOLEAN: {
- bool val;
- elem->GetAsBoolean(&val);
- v8_values.push_back(v8::Boolean::New(val));
- break;
- }
- case Value::TYPE_INTEGER: {
- int val;
- elem->GetAsInteger(&val);
- v8_values.push_back(v8::Integer::New(val));
- break;
- }
- case Value::TYPE_DOUBLE: {
- double val;
- elem->GetAsDouble(&val);
- v8_values.push_back(v8::Number::New(val));
- break;
- }
- case Value::TYPE_STRING: {
- std::string val;
- elem->GetAsString(&val);
- v8_values.push_back(v8::String::New(val.c_str()));
- break;
- }
- default:
- NOTREACHED() << "Unsupported Value type.";
- break;
- }
- }
-
- return v8_values;
-}
-
} // namespace
const char* RendererExtensionBindings::kName =
@@ -299,18 +253,3 @@ v8::Extension* RendererExtensionBindings::Get() {
static v8::Extension* extension = new ExtensionImpl();
return extension;
}
-
-void RendererExtensionBindings::Invoke(const std::string& extension_id,
- const std::string& function_name,
- const ListValue& args,
- RenderView* renderview,
- const GURL& event_url) {
- v8::HandleScope handle_scope;
- std::vector< v8::Handle<v8::Value> > argv = ListValueToV8(args);
- EventBindings::CallFunction(extension_id,
- function_name,
- argv.size(),
- &argv[0],
- renderview,
- event_url);
-}
diff --git a/chrome/renderer/extensions/renderer_extension_bindings.h b/chrome/renderer/extensions/renderer_extension_bindings.h
index 194b0c8..76a1a9c 100644
--- a/chrome/renderer/extensions/renderer_extension_bindings.h
+++ b/chrome/renderer/extensions/renderer_extension_bindings.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,7 +11,6 @@
#include <string>
class GURL;
-class ListValue;
class RenderView;
// This class adds extension-related javascript bindings to a renderer. It is
@@ -23,13 +22,6 @@ class RendererExtensionBindings {
// Creates an instance of the extension.
static v8::Extension* Get();
-
- // Call the given javascript function with the specified arguments.
- static void Invoke(const std::string& extension_id,
- const std::string& function_name,
- const ListValue& args,
- RenderView* renderview,
- const GURL& event_url);
};
#endif // CHROME_RENDERER_EXTENSIONS_RENDERER_EXTENSION_BINDINGS_H_
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 53f1b97..f711060 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -134,6 +134,8 @@
'renderer/transport_texture_host.h',
'renderer/transport_texture_service.cc',
'renderer/transport_texture_service.h',
+ 'renderer/v8_value_converter.cc',
+ 'renderer/v8_value_converter.h',
'renderer/video_decode_accelerator_host.cc',
'renderer/video_decode_accelerator_host.h',
'renderer/webgraphicscontext3d_command_buffer_impl.cc',
diff --git a/content/renderer/render_view.cc b/content/renderer/render_view.cc
index d7da0d0..f324b72 100644
--- a/content/renderer/render_view.cc
+++ b/content/renderer/render_view.cc
@@ -12,6 +12,7 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
+#include "base/json/json_writer.h"
#include "base/lazy_instance.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
@@ -58,6 +59,7 @@
#include "content/renderer/renderer_webapplicationcachehost_impl.h"
#include "content/renderer/renderer_webstoragenamespace_impl.h"
#include "content/renderer/speech_input_dispatcher.h"
+#include "content/renderer/v8_value_converter.h"
#include "content/renderer/web_ui_bindings.h"
#include "content/renderer/webgraphicscontext3d_command_buffer_impl.h"
#include "content/renderer/webplugin_delegate_proxy.h"
@@ -297,39 +299,6 @@ static bool WebAccessibilityNotificationToViewHostMsg(
return true;
}
-// Conversion for the incoming value. The map isn't perfect; v8 has Uint32,
-// and int64 which don't fit as Value::TYPE_INTEGER, so we let them fall into
-// being TYPE_DOUBLEs. Dates are converted to a string (which can then be
-// parsed into a base::Time), as are regexps. Arrays are converted into lists,
-// recursively. We don't deal with binary objects or functions - they become
-// null values.
-static Value* ConvertV8Value(const v8::Handle<v8::Value>& v8value) {
- if (v8value->IsBoolean()) {
- return Value::CreateBooleanValue(v8value->BooleanValue());
- } else if (v8value->IsInt32()) {
- return Value::CreateIntegerValue(v8value->Int32Value());
- } else if (v8value->IsNumber()) {
- return Value::CreateDoubleValue(v8value->NumberValue());
- } else if (v8value->IsString()) {
- return Value::CreateStringValue(*v8::String::Utf8Value(v8value));
- } else if (v8value->IsDate()) {
- v8::Date* date = v8::Date::Cast(*v8value);
- return Value::CreateDoubleValue(date->NumberValue() / 1000.0);
- } else if (v8value->IsRegExp()) {
- return Value::CreateStringValue(
- *v8::String::Utf8Value(v8value->ToString()));
- } else if (v8value->IsArray()) {
- v8::Array* array = v8::Array::Cast(*v8value);
- uint32_t length = array->Length();
- scoped_ptr<ListValue> list(new ListValue);
- for (uint32_t i = 0 ; i < length ; ++i) {
- list->Set(i, ConvertV8Value(array->Get(i)));
- }
- return list.release();
- }
- return Value::CreateNullValue();
-}
-
///////////////////////////////////////////////////////////////////////////////
int32 RenderView::next_page_id_ = 1;
@@ -3370,7 +3339,10 @@ void RenderView::EvaluateScript(const string16& frame_xpath,
v8::HandleScope handle_scope;
v8::Local<v8::Context> context = web_frame->mainWorldScriptContext();
v8::Context::Scope context_scope(context);
- list.Set(0, ConvertV8Value(result));
+ V8ValueConverter converter;
+ converter.set_allow_date(true);
+ converter.set_allow_regexp(true);
+ list.Set(0, converter.FromV8Value(result, context));
} else {
list.Set(0, Value::CreateNullValue());
}
diff --git a/content/renderer/v8_value_converter.cc b/content/renderer/v8_value_converter.cc
new file mode 100644
index 0000000..9b7c2fd
--- /dev/null
+++ b/content/renderer/v8_value_converter.cc
@@ -0,0 +1,156 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/v8_value_converter.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/values.h"
+#include "v8/include/v8.h"
+
+V8ValueConverter::V8ValueConverter() {
+}
+
+v8::Handle<v8::Value> V8ValueConverter::ToV8Value(
+ Value* value, v8::Handle<v8::Context> context) {
+ v8::Context::Scope context_scope(context);
+ return ToV8ValueImpl(value);
+}
+
+Value* V8ValueConverter::FromV8Value(v8::Handle<v8::Value> val,
+ v8::Handle<v8::Context> context) {
+ v8::Context::Scope context_scope(context);
+ return FromV8ValueImpl(val);
+}
+
+v8::Handle<v8::Value> V8ValueConverter::ToV8ValueImpl(Value* value) {
+ CHECK(value);
+ switch (value->GetType()) {
+ case Value::TYPE_NULL:
+ return v8::Null();
+
+ case Value::TYPE_BOOLEAN: {
+ bool val = false;
+ CHECK(value->GetAsBoolean(&val));
+ return v8::Boolean::New(val);
+ }
+
+ case Value::TYPE_INTEGER: {
+ int val = 0;
+ CHECK(value->GetAsInteger(&val));
+ return v8::Integer::New(val);
+ }
+
+ case Value::TYPE_DOUBLE: {
+ double val = 0.0;
+ CHECK(value->GetAsDouble(&val));
+ return v8::Number::New(val);
+ }
+
+ case Value::TYPE_STRING: {
+ std::string val;
+ CHECK(value->GetAsString(&val));
+ return v8::String::New(val.c_str(), val.length());
+ }
+
+ case Value::TYPE_LIST:
+ return ToV8Array(static_cast<ListValue*>(value));
+
+ case Value::TYPE_DICTIONARY:
+ return ToV8Object(static_cast<DictionaryValue*>(value));
+
+ default:
+ NOTREACHED() << "Unexpected value type: " << value->GetType();
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::Value> V8ValueConverter::ToV8Array(ListValue* val) {
+ v8::Handle<v8::Array> result(v8::Array::New(val->GetSize()));
+
+ for (size_t i = 0; i < val->GetSize(); ++i) {
+ Value* child = NULL;
+ CHECK(val->Get(i, &child));
+ result->Set(static_cast<uint32>(i), ToV8ValueImpl(child));
+ }
+
+ return result;
+}
+
+v8::Handle<v8::Value> V8ValueConverter::ToV8Object(DictionaryValue* val) {
+ v8::Handle<v8::Object> result(v8::Object::New());
+
+ for (DictionaryValue::key_iterator iter = val->begin_keys();
+ iter != val->end_keys(); ++iter) {
+ Value* child = NULL;
+ CHECK(val->GetWithoutPathExpansion(*iter, &child));
+ const std::string& key = *iter;
+ result->Set(v8::String::New(key.c_str(), key.length()),
+ ToV8ValueImpl(child));
+ }
+
+ return result;
+}
+
+Value* V8ValueConverter::FromV8ValueImpl(v8::Handle<v8::Value> val) {
+ if (val->IsNull())
+ return Value::CreateNullValue();
+
+ if (val->IsBoolean())
+ return Value::CreateBooleanValue(val->ToBoolean()->Value());
+
+ if (val->IsInt32())
+ return Value::CreateIntegerValue(val->ToInt32()->Value());
+
+ if (val->IsNumber())
+ return Value::CreateDoubleValue(val->ToNumber()->Value());
+
+ if (val->IsString()) {
+ v8::String::Utf8Value utf8(val->ToString());
+ return Value::CreateStringValue(std::string(*utf8, utf8.length()));
+ }
+
+ if (allow_date_ && val->IsDate()) {
+ v8::Date* date = v8::Date::Cast(*val);
+ return Value::CreateDoubleValue(date->NumberValue() / 1000.0);
+ }
+
+ if (allow_regexp_ && val->IsRegExp()) {
+ return Value::CreateStringValue(
+ *v8::String::Utf8Value(val->ToString()));
+ }
+
+ // v8::Value doesn't have a ToArray() method for some reason.
+ if (val->IsArray())
+ return FromV8Array(v8::Handle<v8::Array>::Cast(val));
+
+ if (val->IsObject())
+ return FromV8Object(val->ToObject());
+
+ NOTREACHED() << "Unexpected v8::Value type.";
+ return Value::CreateNullValue();
+}
+
+ListValue* V8ValueConverter::FromV8Array(v8::Handle<v8::Array> val) {
+ ListValue* result = new ListValue();
+ for (uint32 i = 0; i < val->Length(); ++i) {
+ result->Append(FromV8ValueImpl(val->Get(i)));
+ }
+ return result;
+}
+
+DictionaryValue* V8ValueConverter::FromV8Object(v8::Handle<v8::Object> val) {
+ DictionaryValue* result = new DictionaryValue();
+ v8::Handle<v8::Array> property_names(val->GetPropertyNames());
+ for (uint32 i = 0; i < property_names->Length(); ++i) {
+ v8::Handle<v8::String> name(
+ v8::Handle<v8::String>::Cast(property_names->Get(i)));
+ v8::String::Utf8Value name_utf8(name->ToString());
+ result->Set(std::string(*name_utf8, name_utf8.length()),
+ FromV8ValueImpl(val->Get(name)));
+ }
+ return result;
+}
diff --git a/content/renderer/v8_value_converter.h b/content/renderer/v8_value_converter.h
new file mode 100644
index 0000000..4bfce75
--- /dev/null
+++ b/content/renderer/v8_value_converter.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_V8_VALUE_CONVERTER_H_
+#define CHROME_RENDERER_V8_VALUE_CONVERTER_H_
+
+#include "v8/include/v8.h"
+
+class Value;
+class ListValue;
+class DictionaryValue;
+
+// Converts between v8::Value (JavaScript values in the v8 heap) and Chrome's
+// values (from base/values.h). Lists and dictionaries are converted
+// recursively.
+class V8ValueConverter {
+ public:
+ V8ValueConverter();
+
+ bool allow_date() const { return allow_date_; }
+ void set_allow_date(bool val) { allow_date_ = val; }
+
+ bool allow_regexp() const { return allow_regexp_; }
+ void set_allow_regexp(bool val) { allow_regexp_ = val; }
+
+ // Converts Value to v8::Value. Only the JSON types (null, boolean, string,
+ // number, array, and object) are supported. Other types DCHECK and are
+ // replaced with null.
+ v8::Handle<v8::Value> ToV8Value(Value* value,
+ v8::Handle<v8::Context> context);
+
+ // Converts v8::Value to Value. Only the JSON types (null, boolean, string,
+ // number, array, and object) are supported by default, but additional types
+ // can be supported with setters. If a number fits in int32, we will convert
+ // to Value::TYPE_INTEGER instead of Value::TYPE_DOUBLE.
+ Value* FromV8Value(v8::Handle<v8::Value> value,
+ v8::Handle<v8::Context> context);
+
+ private:
+ v8::Handle<v8::Value> ToV8ValueImpl(Value* value);
+ v8::Handle<v8::Value> ToV8Array(ListValue* list);
+ v8::Handle<v8::Value> ToV8Object(DictionaryValue* dictionary);
+
+ Value* FromV8ValueImpl(v8::Handle<v8::Value> value);
+ ListValue* FromV8Array(v8::Handle<v8::Array> array);
+ DictionaryValue* FromV8Object(v8::Handle<v8::Object> object);
+
+ // If true, we will convert Date JavaScript objects to doubles.
+ bool allow_date_;
+
+ // If true, we will convet RegExp JavaScript objects to string.
+ bool allow_regexp_;
+};
+
+#endif // CHROME_RENDERER_V8_VALUE_CONVERTER_H_
diff --git a/content/renderer/v8_value_converter_browsertest.cc b/content/renderer/v8_value_converter_browsertest.cc
new file mode 100644
index 0000000..8c75279
--- /dev/null
+++ b/content/renderer/v8_value_converter_browsertest.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cmath>
+
+#include "base/scoped_ptr.h"
+#include "base/values.h"
+#include "content/renderer/v8_value_converter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "v8/include/v8.h"
+
+class V8ValueConverterTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
+ context_ = v8::Context::New(NULL, global);
+ }
+
+ virtual void TearDown() {
+ context_.Dispose();
+ }
+
+ // Context for the JavaScript in the test.
+ v8::Persistent<v8::Context> context_;
+};
+
+TEST_F(V8ValueConverterTest, BasicRoundTrip) {
+ DictionaryValue original_root;
+ original_root.Set("null", Value::CreateNullValue());
+ original_root.Set("true", Value::CreateBooleanValue(true));
+ original_root.Set("false", Value::CreateBooleanValue(false));
+ original_root.Set("positive-int", Value::CreateIntegerValue(42));
+ original_root.Set("negative-int", Value::CreateIntegerValue(-42));
+ original_root.Set("zero", Value::CreateIntegerValue(0));
+ original_root.Set("double", Value::CreateDoubleValue(88.8));
+ original_root.Set("big-integral-double",
+ Value::CreateDoubleValue(pow(2.0, 53)));
+ original_root.Set("string", Value::CreateStringValue("foobar"));
+ original_root.Set("empty-string", Value::CreateStringValue(""));
+
+ DictionaryValue* original_sub1 = new DictionaryValue();
+ original_sub1->Set("foo", Value::CreateStringValue("bar"));
+ original_sub1->Set("hot", Value::CreateStringValue("dog"));
+ original_root.Set("dictionary", original_sub1);
+ original_root.Set("empty-dictionary", new DictionaryValue());
+
+ ListValue* original_sub2 = new ListValue();
+ original_sub2->Append(Value::CreateStringValue("monkey"));
+ original_sub2->Append(Value::CreateStringValue("balls"));
+ original_root.Set("list", original_sub2);
+ original_root.Set("empty-list", new ListValue());
+
+ v8::Context::Scope context_scope(context_);
+ v8::HandleScope handle_scope;
+
+ V8ValueConverter converter;
+ v8::Handle<v8::Object> v8_object(
+ v8::Handle<v8::Object>::Cast(
+ converter.ToV8Value(&original_root, context_)));
+ ASSERT_FALSE(v8_object.IsEmpty());
+
+ EXPECT_EQ(original_root.size(), v8_object->GetPropertyNames()->Length());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("null"))->IsNull());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("true"))->IsTrue());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("false"))->IsFalse());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("positive-int"))->IsInt32());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("negative-int"))->IsInt32());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("zero"))->IsInt32());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("double"))->IsNumber());
+ EXPECT_TRUE(
+ v8_object->Get(v8::String::New("big-integral-double"))->IsNumber());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("string"))->IsString());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("empty-string"))->IsString());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("dictionary"))->IsObject());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("empty-dictionary"))->IsObject());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("list"))->IsArray());
+ EXPECT_TRUE(v8_object->Get(v8::String::New("empty-list"))->IsArray());
+
+ scoped_ptr<Value> new_root(converter.FromV8Value(v8_object, context_));
+ EXPECT_NE(&original_root, new_root.get());
+ EXPECT_TRUE(original_root.Equals(new_root.get()));
+}