// 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 #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 context) { v8::Isolate* isolate = blink::mainThreadIsolate(); v8::HandleScope handle_scope(isolate); if (context.IsEmpty()) return; v8::Context::Scope context_scope(context); v8::Local 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 void DistillerNativeJavaScript::BindFunctionToObject( v8::Local javascript_object, const std::string& name, const base::Callback 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 GetOrCreateDistillerObject(v8::Isolate* isolate, v8::Local global) { v8::Local distiller_obj; v8::Local 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::Cast(distiller_value); } return distiller_obj; } } // namespace dom_distiller