1 // Copyright 2013 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 "chrome/renderer/extensions/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 "chrome/renderer/extensions/dispatcher.h"
14 #include "chrome/renderer/extensions/extension_helper.h"
15 #include "content/public/renderer/render_view.h"
16 #include "content/public/renderer/render_view_visitor.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
) {
41 virtual bool Visit(content::RenderView
* render_view
) OVERRIDE
{
42 ExtensionHelper
* helper
= ExtensionHelper::Get(render_view
);
44 helper
->dispatcher()->v8_context_set().GetByV8Context(context_
)) {
50 v8::Handle
<v8::Context
> context_
;
51 content::RenderView
* found_
;
53 DISALLOW_COPY_AND_ASSIGN(ByContextFinder
);
56 // Writes |message| to stack to show up in minidump, then crashes.
57 void CheckWithMinidump(const std::string
& message
) {
59 base::debug::Alias(&minidump
);
60 base::snprintf(minidump
, arraysize(minidump
),
61 "e::console: %s", message
.c_str());
62 CHECK(false) << message
;
65 typedef void (*LogMethod
)(v8::Handle
<v8::Context
> context
,
66 const std::string
& message
);
68 void BoundLogMethodCallback(const v8::FunctionCallbackInfo
<v8::Value
>& info
) {
69 LogMethod log_method
= reinterpret_cast<LogMethod
>(
70 info
.Data().As
<v8::External
>()->Value());
72 for (int i
= 0; i
< info
.Length(); ++i
) {
75 message
+= *v8::String::Utf8Value(info
[i
]);
77 (*log_method
)(info
.GetIsolate()->GetCallingContext(), message
);
80 void BindLogMethod(v8::Isolate
* isolate
,
81 v8::Local
<v8::Object
> target
,
82 const std::string
& name
,
83 LogMethod log_method
) {
84 v8::Local
<v8::FunctionTemplate
> tmpl
= v8::FunctionTemplate::New(
86 &BoundLogMethodCallback
,
87 v8::External::New(isolate
, reinterpret_cast<void*>(log_method
)));
88 target
->Set(v8::String::NewFromUtf8(isolate
, name
.c_str()),
94 void Debug(content::RenderView
* render_view
, const std::string
& message
) {
95 AddMessage(render_view
, content::CONSOLE_MESSAGE_LEVEL_DEBUG
, message
);
98 void Log(content::RenderView
* render_view
, const std::string
& message
) {
99 AddMessage(render_view
, content::CONSOLE_MESSAGE_LEVEL_LOG
, message
);
102 void Warn(content::RenderView
* render_view
, const std::string
& message
) {
103 AddMessage(render_view
, content::CONSOLE_MESSAGE_LEVEL_WARNING
, message
);
106 void Error(content::RenderView
* render_view
, const std::string
& message
) {
107 AddMessage(render_view
, content::CONSOLE_MESSAGE_LEVEL_ERROR
, message
);
110 void Fatal(content::RenderView
* render_view
, const std::string
& message
) {
111 Error(render_view
, message
);
112 CheckWithMinidump(message
);
115 void AddMessage(content::RenderView
* render_view
,
116 content::ConsoleMessageLevel level
,
117 const std::string
& message
) {
118 blink::WebView
* web_view
= render_view
->GetWebView();
119 if (!web_view
|| !web_view
->mainFrame())
121 blink::WebConsoleMessage::Level target_level
=
122 blink::WebConsoleMessage::LevelLog
;
124 case content::CONSOLE_MESSAGE_LEVEL_DEBUG
:
125 target_level
= blink::WebConsoleMessage::LevelDebug
;
127 case content::CONSOLE_MESSAGE_LEVEL_LOG
:
128 target_level
= blink::WebConsoleMessage::LevelLog
;
130 case content::CONSOLE_MESSAGE_LEVEL_WARNING
:
131 target_level
= blink::WebConsoleMessage::LevelWarning
;
133 case content::CONSOLE_MESSAGE_LEVEL_ERROR
:
134 target_level
= blink::WebConsoleMessage::LevelError
;
137 web_view
->mainFrame()->addMessageToConsole(
138 blink::WebConsoleMessage(target_level
, base::UTF8ToUTF16(message
)));
141 void Debug(v8::Handle
<v8::Context
> context
, const std::string
& message
) {
142 AddMessage(context
, content::CONSOLE_MESSAGE_LEVEL_DEBUG
, message
);
145 void Log(v8::Handle
<v8::Context
> context
, const std::string
& message
) {
146 AddMessage(context
, content::CONSOLE_MESSAGE_LEVEL_LOG
, message
);
149 void Warn(v8::Handle
<v8::Context
> context
, const std::string
& message
) {
150 AddMessage(context
, content::CONSOLE_MESSAGE_LEVEL_WARNING
, message
);
153 void Error(v8::Handle
<v8::Context
> context
, const std::string
& message
) {
154 AddMessage(context
, content::CONSOLE_MESSAGE_LEVEL_ERROR
, message
);
157 void Fatal(v8::Handle
<v8::Context
> context
, const std::string
& message
) {
158 Error(context
, message
);
159 CheckWithMinidump(message
);
162 void AddMessage(v8::Handle
<v8::Context
> context
,
163 content::ConsoleMessageLevel level
,
164 const std::string
& message
) {
165 if (context
.IsEmpty()) {
166 LOG(WARNING
) << "Could not log \"" << message
<< "\": no context given";
169 content::RenderView
* render_view
= ByContextFinder::Find(context
);
171 LOG(WARNING
) << "Could not log \"" << message
<< "\": no render view found";
174 AddMessage(render_view
, level
, message
);
177 v8::Local
<v8::Object
> AsV8Object() {
178 v8::Isolate
* isolate
= v8::Isolate::GetCurrent();
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