OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/renderer/extensions/console.h" | |
6 | |
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" | |
20 | |
21 namespace extensions { | |
22 namespace console { | |
23 | |
24 namespace { | |
25 | |
26 // Finds the RenderView associated with a context. Note: there will be multiple | |
27 // contexts in each RenderView. | |
28 class ByContextFinder : public content::RenderViewVisitor { | |
29 public: | |
30 static content::RenderView* Find(v8::Handle<v8::Context> context) { | |
31 ByContextFinder finder(context); | |
32 content::RenderView::ForEach(&finder); | |
33 return finder.found_; | |
34 } | |
35 | |
36 private: | |
37 explicit ByContextFinder(v8::Handle<v8::Context> context) | |
38 : context_(context), found_(NULL) { | |
39 } | |
40 | |
41 virtual bool Visit(content::RenderView* render_view) OVERRIDE { | |
42 ExtensionHelper* helper = ExtensionHelper::Get(render_view); | |
43 if (helper && | |
44 helper->dispatcher()->v8_context_set().GetByV8Context(context_)) { | |
45 found_ = render_view; | |
46 } | |
47 return !found_; | |
48 } | |
49 | |
50 v8::Handle<v8::Context> context_; | |
51 content::RenderView* found_; | |
52 | |
53 DISALLOW_COPY_AND_ASSIGN(ByContextFinder); | |
54 }; | |
55 | |
56 // Writes |message| to stack to show up in minidump, then crashes. | |
57 void CheckWithMinidump(const std::string& message) { | |
58 char minidump[1024]; | |
59 base::debug::Alias(&minidump); | |
60 base::snprintf(minidump, arraysize(minidump), | |
61 "e::console: %s", message.c_str()); | |
62 CHECK(false) << message; | |
63 } | |
64 | |
65 typedef void (*LogMethod)(v8::Handle<v8::Context> context, | |
66 const std::string& message); | |
67 | |
68 void BoundLogMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { | |
69 LogMethod log_method = reinterpret_cast<LogMethod>( | |
70 info.Data().As<v8::External>()->Value()); | |
71 std::string message; | |
72 for (int i = 0; i < info.Length(); ++i) { | |
73 if (i > 0) | |
74 message += " "; | |
75 message += *v8::String::Utf8Value(info[i]); | |
76 } | |
77 (*log_method)(info.GetIsolate()->GetCallingContext(), message); | |
78 } | |
79 | |
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( | |
85 isolate, | |
86 &BoundLogMethodCallback, | |
87 v8::External::New(isolate, reinterpret_cast<void*>(log_method))); | |
88 target->Set(v8::String::NewFromUtf8(isolate, name.c_str()), | |
89 tmpl->GetFunction()); | |
90 } | |
91 | |
92 } // namespace | |
93 | |
94 void Debug(content::RenderView* render_view, const std::string& message) { | |
95 AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_DEBUG, message); | |
96 } | |
97 | |
98 void Log(content::RenderView* render_view, const std::string& message) { | |
99 AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_LOG, message); | |
100 } | |
101 | |
102 void Warn(content::RenderView* render_view, const std::string& message) { | |
103 AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_WARNING, message); | |
104 } | |
105 | |
106 void Error(content::RenderView* render_view, const std::string& message) { | |
107 AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_ERROR, message); | |
108 } | |
109 | |
110 void Fatal(content::RenderView* render_view, const std::string& message) { | |
111 Error(render_view, message); | |
112 CheckWithMinidump(message); | |
113 } | |
114 | |
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()) | |
120 return; | |
121 blink::WebConsoleMessage::Level target_level = | |
122 blink::WebConsoleMessage::LevelLog; | |
123 switch (level) { | |
124 case content::CONSOLE_MESSAGE_LEVEL_DEBUG: | |
125 target_level = blink::WebConsoleMessage::LevelDebug; | |
126 break; | |
127 case content::CONSOLE_MESSAGE_LEVEL_LOG: | |
128 target_level = blink::WebConsoleMessage::LevelLog; | |
129 break; | |
130 case content::CONSOLE_MESSAGE_LEVEL_WARNING: | |
131 target_level = blink::WebConsoleMessage::LevelWarning; | |
132 break; | |
133 case content::CONSOLE_MESSAGE_LEVEL_ERROR: | |
134 target_level = blink::WebConsoleMessage::LevelError; | |
135 break; | |
136 } | |
137 web_view->mainFrame()->addMessageToConsole( | |
138 blink::WebConsoleMessage(target_level, base::UTF8ToUTF16(message))); | |
139 } | |
140 | |
141 void Debug(v8::Handle<v8::Context> context, const std::string& message) { | |
142 AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_DEBUG, message); | |
143 } | |
144 | |
145 void Log(v8::Handle<v8::Context> context, const std::string& message) { | |
146 AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_LOG, message); | |
147 } | |
148 | |
149 void Warn(v8::Handle<v8::Context> context, const std::string& message) { | |
150 AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_WARNING, message); | |
151 } | |
152 | |
153 void Error(v8::Handle<v8::Context> context, const std::string& message) { | |
154 AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_ERROR, message); | |
155 } | |
156 | |
157 void Fatal(v8::Handle<v8::Context> context, const std::string& message) { | |
158 Error(context, message); | |
159 CheckWithMinidump(message); | |
160 } | |
161 | |
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"; | |
167 return; | |
168 } | |
169 content::RenderView* render_view = ByContextFinder::Find(context); | |
170 if (!render_view) { | |
171 LOG(WARNING) << "Could not log \"" << message << "\": no render view found"; | |
172 return; | |
173 } | |
174 AddMessage(render_view, level, message); | |
175 } | |
176 | |
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); | |
186 } | |
187 | |
188 } // namespace console | |
189 } // namespace extensions | |
OLD | NEW |