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.
5 #include "extensions/renderer/console.h"
7 #include "base/compiler_specific.h"
8 #include "base/debug/alias.h"
9 #include "base/lazy_instance.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/public/renderer/render_view.h"
14 #include "content/public/renderer/render_view_visitor.h"
15 #include "extensions/renderer/dispatcher.h"
16 #include "extensions/renderer/extension_helper.h"
17 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
18 #include "third_party/WebKit/public/web/WebFrame.h"
19 #include "third_party/WebKit/public/web/WebView.h"
21 namespace extensions
{
26 // Finds the RenderView associated with a context. Note: there will be multiple
27 // contexts in each RenderView.
28 class ByContextFinder
: public content::RenderViewVisitor
{
30 static content::RenderView
* Find(v8::Handle
<v8::Context
> context
) {
31 ByContextFinder
finder(context
);
32 content::RenderView::ForEach(&finder
);
37 explicit ByContextFinder(v8::Handle
<v8::Context
> context
)
38 : context_(context
), found_(NULL
) {}
40 bool Visit(content::RenderView
* render_view
) override
{
41 ExtensionHelper
* helper
= ExtensionHelper::Get(render_view
);
43 ScriptContext
* script_context
=
44 helper
->dispatcher()->script_context_set().GetByV8Context(context_
);
45 if (script_context
&& script_context
->GetRenderView() == render_view
)
51 v8::Handle
<v8::Context
> context_
;
52 content::RenderView
* found_
;
54 DISALLOW_COPY_AND_ASSIGN(ByContextFinder
);
57 // Writes |message| to stack to show up in minidump, then crashes.
58 void CheckWithMinidump(const std::string
& message
) {
60 base::debug::Alias(&minidump
);
62 minidump
, arraysize(minidump
), "e::console: %s", message
.c_str());
63 CHECK(false) << message
;
66 typedef void (*LogMethod
)(v8::Handle
<v8::Context
> context
,
67 const std::string
& message
);
69 void BoundLogMethodCallback(const v8::FunctionCallbackInfo
<v8::Value
>& info
) {
70 LogMethod log_method
=
71 reinterpret_cast<LogMethod
>(info
.Data().As
<v8::External
>()->Value());
73 for (int i
= 0; i
< info
.Length(); ++i
) {
76 message
+= *v8::String::Utf8Value(info
[i
]);
78 (*log_method
)(info
.GetIsolate()->GetCallingContext(), message
);
81 void BindLogMethod(v8::Isolate
* isolate
,
82 v8::Local
<v8::Object
> target
,
83 const std::string
& name
,
84 LogMethod log_method
) {
85 v8::Local
<v8::FunctionTemplate
> tmpl
= v8::FunctionTemplate::New(
87 &BoundLogMethodCallback
,
88 v8::External::New(isolate
, reinterpret_cast<void*>(log_method
)));
89 target
->Set(v8::String::NewFromUtf8(isolate
, name
.c_str()),
95 void Debug(content::RenderView
* render_view
, const std::string
& message
) {
96 AddMessage(render_view
, content::CONSOLE_MESSAGE_LEVEL_DEBUG
, message
);
99 void Log(content::RenderView
* render_view
, const std::string
& message
) {
100 AddMessage(render_view
, content::CONSOLE_MESSAGE_LEVEL_LOG
, message
);
103 void Warn(content::RenderView
* render_view
, const std::string
& message
) {
104 AddMessage(render_view
, content::CONSOLE_MESSAGE_LEVEL_WARNING
, message
);
107 void Error(content::RenderView
* render_view
, const std::string
& message
) {
108 AddMessage(render_view
, content::CONSOLE_MESSAGE_LEVEL_ERROR
, message
);
111 void Fatal(content::RenderView
* render_view
, const std::string
& message
) {
112 Error(render_view
, message
);
113 CheckWithMinidump(message
);
116 void AddMessage(content::RenderView
* render_view
,
117 content::ConsoleMessageLevel level
,
118 const std::string
& message
) {
119 blink::WebView
* web_view
= render_view
->GetWebView();
120 if (!web_view
|| !web_view
->mainFrame())
122 blink::WebConsoleMessage::Level target_level
=
123 blink::WebConsoleMessage::LevelLog
;
125 case content::CONSOLE_MESSAGE_LEVEL_DEBUG
:
126 target_level
= blink::WebConsoleMessage::LevelDebug
;
128 case content::CONSOLE_MESSAGE_LEVEL_LOG
:
129 target_level
= blink::WebConsoleMessage::LevelLog
;
131 case content::CONSOLE_MESSAGE_LEVEL_WARNING
:
132 target_level
= blink::WebConsoleMessage::LevelWarning
;
134 case content::CONSOLE_MESSAGE_LEVEL_ERROR
:
135 target_level
= blink::WebConsoleMessage::LevelError
;
138 web_view
->mainFrame()->addMessageToConsole(
139 blink::WebConsoleMessage(target_level
, base::UTF8ToUTF16(message
)));
142 void Debug(v8::Handle
<v8::Context
> context
, const std::string
& message
) {
143 AddMessage(context
, content::CONSOLE_MESSAGE_LEVEL_DEBUG
, message
);
146 void Log(v8::Handle
<v8::Context
> context
, const std::string
& message
) {
147 AddMessage(context
, content::CONSOLE_MESSAGE_LEVEL_LOG
, message
);
150 void Warn(v8::Handle
<v8::Context
> context
, const std::string
& message
) {
151 AddMessage(context
, content::CONSOLE_MESSAGE_LEVEL_WARNING
, message
);
154 void Error(v8::Handle
<v8::Context
> context
, const std::string
& message
) {
155 AddMessage(context
, content::CONSOLE_MESSAGE_LEVEL_ERROR
, message
);
158 void Fatal(v8::Handle
<v8::Context
> context
, const std::string
& message
) {
159 Error(context
, message
);
160 CheckWithMinidump(message
);
163 void AddMessage(v8::Handle
<v8::Context
> context
,
164 content::ConsoleMessageLevel level
,
165 const std::string
& message
) {
166 if (context
.IsEmpty()) {
167 LOG(WARNING
) << "Could not log \"" << message
<< "\": no context given";
170 content::RenderView
* render_view
= ByContextFinder::Find(context
);
172 LOG(WARNING
) << "Could not log \"" << message
<< "\": no render view found";
175 AddMessage(render_view
, level
, message
);
178 v8::Local
<v8::Object
> AsV8Object(v8::Isolate
* isolate
) {
179 v8::EscapableHandleScope
handle_scope(isolate
);
180 v8::Local
<v8::Object
> console_object
= v8::Object::New(isolate
);
181 BindLogMethod(isolate
, console_object
, "debug", &Debug
);
182 BindLogMethod(isolate
, console_object
, "log", &Log
);
183 BindLogMethod(isolate
, console_object
, "warn", &Warn
);
184 BindLogMethod(isolate
, console_object
, "error", &Error
);
185 return handle_scope
.Escape(console_object
);
188 } // namespace console
189 } // namespace extensions