1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "extensions/renderer/utils_native_handler.h"
6
7#include "base/strings/stringprintf.h"
8#include "extensions/renderer/script_context.h"
9#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
10#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
11
12namespace extensions {
13
14UtilsNativeHandler::UtilsNativeHandler(ScriptContext* context)
15    : ObjectBackedNativeHandler(context) {
16  RouteFunction("createClassWrapper",
17                base::Bind(&UtilsNativeHandler::CreateClassWrapper,
18                           base::Unretained(this)));
19  RouteFunction(
20      "deepCopy",
21      base::Bind(&UtilsNativeHandler::DeepCopy, base::Unretained(this)));
22}
23
24UtilsNativeHandler::~UtilsNativeHandler() {}
25
26void UtilsNativeHandler::CreateClassWrapper(
27    const v8::FunctionCallbackInfo<v8::Value>& args) {
28  CHECK_EQ(3, args.Length());
29  CHECK(args[0]->IsString());
30  std::string name = *v8::String::Utf8Value(args[0]);
31  CHECK(args[1]->IsObject());
32  v8::Local<v8::Object> cls = args[1].As<v8::Object>();
33  CHECK(args[2]->IsObject() || args[2]->IsUndefined());
34  v8::Local<v8::Value> superclass = args[2];
35
36  v8::HandleScope handle_scope(GetIsolate());
37  // TODO(fsamuel): Consider moving the source wrapping to ModuleSystem.
38  v8::Handle<v8::String> source = v8::String::NewFromUtf8(
39      GetIsolate(),
40      base::StringPrintf(
41          "(function($Object, $Function, privates, cls, superclass) {"
42          "'use strict';\n"
43          "  function %s() {\n"
44          "    var privateObj = $Object.create(cls.prototype);\n"
45          "    $Function.apply(cls, privateObj, arguments);\n"
46          "    privateObj.wrapper = this;\n"
47          "    privates(this).impl = privateObj;\n"
48          "  };\n"
49          "  if (superclass) {\n"
50          "    %s.prototype = Object.create(superclass.prototype);\n"
51          "  }\n"
52          "  return %s;\n"
53          "})",
54          name.c_str(),
55          name.c_str(),
56          name.c_str()).c_str());
57  v8::Handle<v8::Value> func_as_value = context()->module_system()->RunString(
58      source, v8::String::NewFromUtf8(GetIsolate(), name.c_str()));
59  if (func_as_value.IsEmpty() || func_as_value->IsUndefined()) {
60    args.GetReturnValue().SetUndefined();
61    return;
62  }
63
64  // TODO(fsamuel): Move privates from ModuleSystem to a shared location.
65  v8::Handle<v8::Object> natives(context()->module_system()->NewInstance());
66  CHECK(!natives.IsEmpty());  // this can happen if v8 has issues
67  v8::Handle<v8::Function> func = func_as_value.As<v8::Function>();
68  v8::Handle<v8::Value> func_args[] = {
69      context()->safe_builtins()->GetObjekt(),
70      context()->safe_builtins()->GetFunction(),
71      natives->Get(v8::String::NewFromUtf8(
72          GetIsolate(), "privates", v8::String::kInternalizedString)),
73      cls,
74      superclass};
75  v8::Local<v8::Value> result;
76  {
77    v8::TryCatch try_catch;
78    try_catch.SetCaptureMessage(true);
79    result = context()->CallFunction(func, arraysize(func_args), func_args);
80    if (try_catch.HasCaught()) {
81      args.GetReturnValue().SetUndefined();
82      return;
83    }
84  }
85  args.GetReturnValue().Set(result);
86}
87
88void UtilsNativeHandler::DeepCopy(
89    const v8::FunctionCallbackInfo<v8::Value>& args) {
90  CHECK_EQ(1, args.Length());
91  args.GetReturnValue().Set(
92      blink::WebSerializedScriptValue::serialize(args[0]).deserialize());
93}
94
95}  // namespace extensions
96