blob: 14a3411548155a95502af6d04f334c3f0bb7ebac [file] [log] [blame]
// Copyright 2015 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 "components/dom_distiller/content/renderer/distiller_native_javascript.h"
#include <string>
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "components/dom_distiller/content/common/distiller_javascript_service.mojom.h"
#include "content/public/common/service_registry.h"
#include "content/public/renderer/render_frame.h"
#include "gin/arguments.h"
#include "gin/function_template.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "v8/include/v8.h"
using blink::WebLocalFrame;
namespace dom_distiller {
DistillerNativeJavaScript::DistillerNativeJavaScript(
content::RenderFrame* render_frame)
: render_frame_(render_frame) {}
DistillerNativeJavaScript::~DistillerNativeJavaScript() {}
void DistillerNativeJavaScript::AddJavaScriptObjectToFrame(
v8::Local<v8::Context> context) {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
if (context.IsEmpty())
return;
v8::Context::Scope context_scope(context);
v8::Local<v8::Object> distiller_obj =
GetOrCreateDistillerObject(isolate, context->Global());
EnsureServiceConnected();
// Some of the JavaScript functions require extra work to be done when it is
// called, so they have wrapper functions maintained in this class.
BindFunctionToObject(
distiller_obj,
"echo",
base::Bind(
&DistillerNativeJavaScript::DistillerEcho, base::Unretained(this)));
// Many functions can simply call the Mojo interface directly and have no
// wrapper function for binding. Note that calling distiller_js_service.get()
// does not transfer ownership of the interface.
BindFunctionToObject(
distiller_obj,
"sendFeedback",
base::Bind(
&DistillerJavaScriptService::HandleDistillerFeedbackCall,
base::Unretained(distiller_js_service_.get())));
BindFunctionToObject(
distiller_obj,
"closePanel",
base::Bind(
&DistillerJavaScriptService::HandleDistillerClosePanelCall,
base::Unretained(distiller_js_service_.get())));
BindFunctionToObject(
distiller_obj,
"openSettings",
base::Bind(
&DistillerJavaScriptService::HandleDistillerOpenSettingsCall,
base::Unretained(distiller_js_service_.get())));
}
template<typename Sig>
void DistillerNativeJavaScript::BindFunctionToObject(
v8::Local<v8::Object> javascript_object,
const std::string& name,
const base::Callback<Sig> callback) {
// Get the isolate associated with this object.
v8::Isolate* isolate = javascript_object->GetIsolate();
javascript_object->Set(
gin::StringToSymbol(isolate, name),
gin::CreateFunctionTemplate(isolate, callback)->GetFunction());
}
void DistillerNativeJavaScript::EnsureServiceConnected() {
if (!distiller_js_service_ || !distiller_js_service_.is_bound()) {
render_frame_->GetServiceRegistry()->ConnectToRemoteService(
mojo::GetProxy(&distiller_js_service_));
}
}
std::string DistillerNativeJavaScript::DistillerEcho(
const std::string& message) {
EnsureServiceConnected();
// TODO(mdjones): It is possible and beneficial to have information
// returned from the browser process with these calls. The problem
// is waiting blocks this process.
distiller_js_service_->HandleDistillerEchoCall(message);
return message;
}
v8::Local<v8::Object> GetOrCreateDistillerObject(v8::Isolate* isolate,
v8::Local<v8::Object> global) {
v8::Local<v8::Object> distiller_obj;
v8::Local<v8::Value> distiller_value =
global->Get(gin::StringToV8(isolate, "distiller"));
if (distiller_value.IsEmpty() || !distiller_value->IsObject()) {
distiller_obj = v8::Object::New(isolate);
global->Set(gin::StringToSymbol(isolate, "distiller"), distiller_obj);
} else {
distiller_obj = v8::Local<v8::Object>::Cast(distiller_value);
}
return distiller_obj;
}
} // namespace dom_distiller