OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/renderer/console.h" | 5 #include "extensions/renderer/console.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/debug/alias.h" | 8 #include "base/debug/alias.h" |
9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
11 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
13 #include "content/public/renderer/render_view.h" | 13 #include "content/public/renderer/render_frame.h" |
14 #include "content/public/renderer/render_view_visitor.h" | 14 #include "extensions/renderer/extension_frame_helper.h" |
15 #include "extensions/renderer/dispatcher.h" | 15 #include "extensions/renderer/script_context.h" |
16 #include "extensions/renderer/extension_helper.h" | 16 #include "extensions/renderer/script_context_set.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 | 17 |
21 namespace extensions { | 18 namespace extensions { |
22 namespace console { | 19 namespace console { |
23 | 20 |
24 namespace { | 21 namespace { |
25 | 22 |
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::Local<v8::Context> context) { | |
31 ByContextFinder finder(context); | |
32 content::RenderView::ForEach(&finder); | |
33 return finder.found_; | |
34 } | |
35 | |
36 private: | |
37 explicit ByContextFinder(v8::Local<v8::Context> context) | |
38 : context_(context), found_(NULL) {} | |
39 | |
40 bool Visit(content::RenderView* render_view) override { | |
41 ExtensionHelper* helper = ExtensionHelper::Get(render_view); | |
42 if (helper) { | |
43 ScriptContext* script_context = | |
44 helper->dispatcher()->script_context_set().GetByV8Context(context_); | |
45 if (script_context && script_context->GetRenderView() == render_view) | |
46 found_ = render_view; | |
47 } | |
48 return !found_; | |
49 } | |
50 | |
51 v8::Local<v8::Context> context_; | |
52 content::RenderView* found_; | |
53 | |
54 DISALLOW_COPY_AND_ASSIGN(ByContextFinder); | |
55 }; | |
56 | |
57 // Writes |message| to stack to show up in minidump, then crashes. | 23 // Writes |message| to stack to show up in minidump, then crashes. |
58 void CheckWithMinidump(const std::string& message) { | 24 void CheckWithMinidump(const std::string& message) { |
59 char minidump[1024]; | 25 char minidump[1024]; |
60 base::debug::Alias(&minidump); | 26 base::debug::Alias(&minidump); |
61 base::snprintf( | 27 base::snprintf( |
62 minidump, arraysize(minidump), "e::console: %s", message.c_str()); | 28 minidump, arraysize(minidump), "e::console: %s", message.c_str()); |
63 CHECK(false) << message; | 29 CHECK(false) << message; |
64 } | 30 } |
65 | 31 |
66 typedef void (*LogMethod)(v8::Local<v8::Context> context, | 32 typedef void (*LogMethod)(content::RenderFrame* render_frame, |
67 const std::string& message); | 33 const std::string& message); |
68 | 34 |
69 void BoundLogMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { | 35 void BoundLogMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { |
70 LogMethod log_method = | |
71 reinterpret_cast<LogMethod>(info.Data().As<v8::External>()->Value()); | |
72 std::string message; | 36 std::string message; |
73 for (int i = 0; i < info.Length(); ++i) { | 37 for (int i = 0; i < info.Length(); ++i) { |
74 if (i > 0) | 38 if (i > 0) |
75 message += " "; | 39 message += " "; |
76 message += *v8::String::Utf8Value(info[i]); | 40 message += *v8::String::Utf8Value(info[i]); |
77 } | 41 } |
78 (*log_method)(info.GetIsolate()->GetCallingContext(), message); | 42 |
| 43 v8::Local<v8::Context> context = info.GetIsolate()->GetCallingContext(); |
| 44 if (context.IsEmpty()) { |
| 45 LOG(WARNING) << "Could not log \"" << message << "\": no context given"; |
| 46 return; |
| 47 } |
| 48 |
| 49 ScriptContext* script_context = |
| 50 ScriptContextSet::GetContextByV8Context(context); |
| 51 LogMethod log_method = |
| 52 reinterpret_cast<LogMethod>(info.Data().As<v8::External>()->Value()); |
| 53 (*log_method)(script_context ? script_context->GetRenderFrame() : nullptr, |
| 54 message); |
79 } | 55 } |
80 | 56 |
81 void BindLogMethod(v8::Isolate* isolate, | 57 void BindLogMethod(v8::Isolate* isolate, |
82 v8::Local<v8::Object> target, | 58 v8::Local<v8::Object> target, |
83 const std::string& name, | 59 const std::string& name, |
84 LogMethod log_method) { | 60 LogMethod log_method) { |
85 v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New( | 61 v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New( |
86 isolate, | 62 isolate, |
87 &BoundLogMethodCallback, | 63 &BoundLogMethodCallback, |
88 v8::External::New(isolate, reinterpret_cast<void*>(log_method))); | 64 v8::External::New(isolate, reinterpret_cast<void*>(log_method))); |
89 target->Set(v8::String::NewFromUtf8(isolate, name.c_str()), | 65 target->Set(v8::String::NewFromUtf8(isolate, name.c_str()), |
90 tmpl->GetFunction()); | 66 tmpl->GetFunction()); |
91 } | 67 } |
92 | 68 |
93 } // namespace | 69 } // namespace |
94 | 70 |
95 void Debug(content::RenderView* render_view, const std::string& message) { | 71 void Debug(content::RenderFrame* render_frame, const std::string& message) { |
96 AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_DEBUG, message); | 72 AddMessage(render_frame, content::CONSOLE_MESSAGE_LEVEL_DEBUG, message); |
97 } | 73 } |
98 | 74 |
99 void Log(content::RenderView* render_view, const std::string& message) { | 75 void Log(content::RenderFrame* render_frame, const std::string& message) { |
100 AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_LOG, message); | 76 AddMessage(render_frame, content::CONSOLE_MESSAGE_LEVEL_LOG, message); |
101 } | 77 } |
102 | 78 |
103 void Warn(content::RenderView* render_view, const std::string& message) { | 79 void Warn(content::RenderFrame* render_frame, const std::string& message) { |
104 AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_WARNING, message); | 80 AddMessage(render_frame, content::CONSOLE_MESSAGE_LEVEL_WARNING, message); |
105 } | 81 } |
106 | 82 |
107 void Error(content::RenderView* render_view, const std::string& message) { | 83 void Error(content::RenderFrame* render_frame, const std::string& message) { |
108 AddMessage(render_view, content::CONSOLE_MESSAGE_LEVEL_ERROR, message); | 84 AddMessage(render_frame, content::CONSOLE_MESSAGE_LEVEL_ERROR, message); |
109 } | 85 } |
110 | 86 |
111 void Fatal(content::RenderView* render_view, const std::string& message) { | 87 void Fatal(content::RenderFrame* render_frame, const std::string& message) { |
112 Error(render_view, message); | 88 Error(render_frame, message); |
113 CheckWithMinidump(message); | 89 CheckWithMinidump(message); |
114 } | 90 } |
115 | 91 |
116 void AddMessage(content::RenderView* render_view, | 92 void AddMessage(content::RenderFrame* render_frame, |
117 content::ConsoleMessageLevel level, | 93 content::ConsoleMessageLevel level, |
118 const std::string& message) { | 94 const std::string& message) { |
119 blink::WebView* web_view = render_view->GetWebView(); | 95 if (!render_frame) { |
120 if (!web_view || !web_view->mainFrame()) | 96 LOG(WARNING) << "Could not log \"" << message |
121 return; | 97 << "\": no render frame found"; |
122 blink::WebConsoleMessage::Level target_level = | 98 } else { |
123 blink::WebConsoleMessage::LevelLog; | 99 render_frame->AddMessageToConsole(level, message); |
124 switch (level) { | |
125 case content::CONSOLE_MESSAGE_LEVEL_DEBUG: | |
126 target_level = blink::WebConsoleMessage::LevelDebug; | |
127 break; | |
128 case content::CONSOLE_MESSAGE_LEVEL_LOG: | |
129 target_level = blink::WebConsoleMessage::LevelLog; | |
130 break; | |
131 case content::CONSOLE_MESSAGE_LEVEL_WARNING: | |
132 target_level = blink::WebConsoleMessage::LevelWarning; | |
133 break; | |
134 case content::CONSOLE_MESSAGE_LEVEL_ERROR: | |
135 target_level = blink::WebConsoleMessage::LevelError; | |
136 break; | |
137 } | 100 } |
138 web_view->mainFrame()->addMessageToConsole( | |
139 blink::WebConsoleMessage(target_level, base::UTF8ToUTF16(message))); | |
140 } | |
141 | |
142 void Debug(v8::Local<v8::Context> context, const std::string& message) { | |
143 AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_DEBUG, message); | |
144 } | |
145 | |
146 void Log(v8::Local<v8::Context> context, const std::string& message) { | |
147 AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_LOG, message); | |
148 } | |
149 | |
150 void Warn(v8::Local<v8::Context> context, const std::string& message) { | |
151 AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_WARNING, message); | |
152 } | |
153 | |
154 void Error(v8::Local<v8::Context> context, const std::string& message) { | |
155 AddMessage(context, content::CONSOLE_MESSAGE_LEVEL_ERROR, message); | |
156 } | |
157 | |
158 void Fatal(v8::Local<v8::Context> context, const std::string& message) { | |
159 Error(context, message); | |
160 CheckWithMinidump(message); | |
161 } | |
162 | |
163 void AddMessage(v8::Local<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"; | |
168 return; | |
169 } | |
170 content::RenderView* render_view = ByContextFinder::Find(context); | |
171 if (!render_view) { | |
172 LOG(WARNING) << "Could not log \"" << message << "\": no render view found"; | |
173 return; | |
174 } | |
175 AddMessage(render_view, level, message); | |
176 } | 101 } |
177 | 102 |
178 v8::Local<v8::Object> AsV8Object(v8::Isolate* isolate) { | 103 v8::Local<v8::Object> AsV8Object(v8::Isolate* isolate) { |
179 v8::EscapableHandleScope handle_scope(isolate); | 104 v8::EscapableHandleScope handle_scope(isolate); |
180 v8::Local<v8::Object> console_object = v8::Object::New(isolate); | 105 v8::Local<v8::Object> console_object = v8::Object::New(isolate); |
181 BindLogMethod(isolate, console_object, "debug", &Debug); | 106 BindLogMethod(isolate, console_object, "debug", &Debug); |
182 BindLogMethod(isolate, console_object, "log", &Log); | 107 BindLogMethod(isolate, console_object, "log", &Log); |
183 BindLogMethod(isolate, console_object, "warn", &Warn); | 108 BindLogMethod(isolate, console_object, "warn", &Warn); |
184 BindLogMethod(isolate, console_object, "error", &Error); | 109 BindLogMethod(isolate, console_object, "error", &Error); |
185 return handle_scope.Escape(console_object); | 110 return handle_scope.Escape(console_object); |
186 } | 111 } |
187 | 112 |
188 } // namespace console | 113 } // namespace console |
189 } // namespace extensions | 114 } // namespace extensions |
OLD | NEW |