OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/renderer/automation/automation_renderer_helper.h" | 5 #include "chrome/renderer/automation/automation_renderer_helper.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/json/json_writer.h" |
| 11 #include "base/stringprintf.h" |
| 12 #include "base/string_split.h" |
| 13 #include "base/utf_string_conversions.h" |
| 14 #include "base/values.h" |
| 15 #include "chrome/common/automation_events.h" |
10 #include "chrome/common/automation_messages.h" | 16 #include "chrome/common/automation_messages.h" |
11 #include "content/public/renderer/render_view.h" | 17 #include "content/public/renderer/render_view.h" |
| 18 #include "content/public/renderer/v8_value_converter.h" |
12 #include "skia/ext/platform_canvas.h" | 19 #include "skia/ext/platform_canvas.h" |
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | |
14 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" | 20 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" |
15 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h" | 21 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h" |
| 22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| 23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
| 24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h" |
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | 25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
17 #include "ui/gfx/codec/png_codec.h" | 26 #include "ui/gfx/codec/png_codec.h" |
| 27 #include "ui/gfx/point.h" |
18 #include "ui/gfx/rect.h" | 28 #include "ui/gfx/rect.h" |
| 29 #include "v8/include/v8.h" |
19 #include "webkit/glue/webkit_glue.h" | 30 #include "webkit/glue/webkit_glue.h" |
20 | 31 |
21 #if !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) | 32 #if !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) |
22 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" | 33 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" |
23 #endif // !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) | 34 #endif // !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) |
24 | 35 |
25 using WebKit::WebFrame; | 36 using WebKit::WebFrame; |
26 using WebKit::WebSize; | 37 using WebKit::WebSize; |
27 using WebKit::WebURL; | 38 using WebKit::WebURL; |
28 using WebKit::WebView; | 39 using WebKit::WebView; |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 // message data. | 110 // message data. |
100 if (success && png_data.size() > IPC::Channel::kMaximumMessageSize - 1024) { | 111 if (success && png_data.size() > IPC::Channel::kMaximumMessageSize - 1024) { |
101 png_data.clear(); | 112 png_data.clear(); |
102 success = false; | 113 success = false; |
103 error_msg = "image is too large to be transferred over ipc"; | 114 error_msg = "image is too large to be transferred over ipc"; |
104 } | 115 } |
105 Send(new AutomationMsg_SnapshotEntirePageACK( | 116 Send(new AutomationMsg_SnapshotEntirePageACK( |
106 routing_id(), success, png_data, error_msg)); | 117 routing_id(), success, png_data, error_msg)); |
107 } | 118 } |
108 | 119 |
| 120 namespace { |
| 121 |
| 122 scoped_ptr<base::Value> EvaluateScriptInFrame(WebFrame* web_frame, |
| 123 const std::string& script) { |
| 124 v8::Handle<v8::Value> result = web_frame->executeScriptAndReturnValue( |
| 125 WebKit::WebScriptSource(UTF8ToUTF16(script))); |
| 126 if (!result.IsEmpty()) { |
| 127 v8::HandleScope handle_scope; |
| 128 v8::Local<v8::Context> context = web_frame->mainWorldScriptContext(); |
| 129 v8::Context::Scope context_scope(context); |
| 130 scoped_ptr<content::V8ValueConverter> converter( |
| 131 content::V8ValueConverter::create()); |
| 132 return scoped_ptr<base::Value>(converter->FromV8Value(result, context)); |
| 133 } else { |
| 134 return scoped_ptr<base::Value>(base::Value::CreateNullValue()); |
| 135 } |
| 136 } |
| 137 |
| 138 WebFrame* FrameFromXPath(WebView* view, const string16& frame_xpath) { |
| 139 WebFrame* frame = view->mainFrame(); |
| 140 if (frame_xpath.empty()) |
| 141 return frame; |
| 142 |
| 143 std::vector<string16> xpaths; |
| 144 base::SplitString(frame_xpath, '\n', &xpaths); |
| 145 for (std::vector<string16>::const_iterator i = xpaths.begin(); |
| 146 frame && i != xpaths.end(); ++i) { |
| 147 frame = frame->findChildByExpression(*i); |
| 148 } |
| 149 return frame; |
| 150 } |
| 151 |
| 152 bool EvaluateScriptChainHelper( |
| 153 WebView* web_view, |
| 154 const std::string& script, |
| 155 const std::string& frame_xpath, |
| 156 scoped_ptr<base::DictionaryValue>* result, |
| 157 std::string* error_msg) { |
| 158 WebFrame* web_frame = FrameFromXPath(web_view, UTF8ToUTF16(frame_xpath)); |
| 159 if (!web_frame) { |
| 160 *error_msg = "Failed to locate frame by xpath: " + frame_xpath; |
| 161 return false; |
| 162 } |
| 163 scoped_ptr<base::Value> script_value = |
| 164 EvaluateScriptInFrame(web_frame, script); |
| 165 base::DictionaryValue* dict; |
| 166 if (!script_value.get() || !script_value->GetAsDictionary(&dict)) { |
| 167 *error_msg = "Script did not return an object"; |
| 168 return false; |
| 169 } |
| 170 base::Value* error_value; |
| 171 if (dict->Get("error", &error_value)) { |
| 172 base::JSONWriter::Write(error_value, error_msg); |
| 173 return false; |
| 174 } |
| 175 result->reset(static_cast<base::DictionaryValue*>(script_value.release())); |
| 176 return true; |
| 177 } |
| 178 |
| 179 } // namespace |
| 180 |
| 181 bool AutomationRendererHelper::EvaluateScriptChain( |
| 182 const std::vector<ScriptEvaluationRequest>& script_chain, |
| 183 scoped_ptr<base::DictionaryValue>* result, |
| 184 std::string* error_msg) { |
| 185 CHECK(!script_chain.empty()); |
| 186 WebView* web_view = render_view()->GetWebView(); |
| 187 scoped_ptr<base::DictionaryValue> temp_result; |
| 188 for (size_t i = 0; i < script_chain.size(); ++i) { |
| 189 std::string args_utf8 = "null"; |
| 190 if (temp_result.get()) |
| 191 base::JSONWriter::Write(temp_result.get(), &args_utf8); |
| 192 std::string wrapper_script = base::StringPrintf( |
| 193 "(function(){return %s\n}).apply(null, [%s])", |
| 194 script_chain[i].script.c_str(), args_utf8.c_str()); |
| 195 if (!EvaluateScriptChainHelper(web_view, wrapper_script, |
| 196 script_chain[i].frame_xpath, |
| 197 &temp_result, error_msg)) { |
| 198 return false; |
| 199 } |
| 200 } |
| 201 std::string result_str; |
| 202 base::JSONWriter::Write(temp_result.get(), &result_str); |
| 203 result->reset(temp_result.release()); |
| 204 return true; |
| 205 } |
| 206 |
| 207 bool AutomationRendererHelper::ProcessMouseEvent( |
| 208 const AutomationMouseEvent& event, |
| 209 std::string* error_msg) { |
| 210 WebView* web_view = render_view()->GetWebView(); |
| 211 if (!web_view) { |
| 212 *error_msg = "Failed to process mouse event because webview does not exist"; |
| 213 return false; |
| 214 } |
| 215 WebKit::WebMouseEvent mouse_event = event.mouse_event; |
| 216 if (!event.location_script_chain.empty()) { |
| 217 scoped_ptr<base::DictionaryValue> result; |
| 218 if (!EvaluateScriptChain(event.location_script_chain, &result, error_msg)) |
| 219 return false; |
| 220 int x, y; |
| 221 if (!result->GetInteger("x", &x) || |
| 222 !result->GetInteger("y", &y)) { |
| 223 *error_msg = "Script did not return an (x,y) location"; |
| 224 return false; |
| 225 } |
| 226 mouse_event.x = x; |
| 227 mouse_event.y = y; |
| 228 } |
| 229 Send(new AutomationMsg_WillProcessMouseEventAt( |
| 230 routing_id(), |
| 231 gfx::Point(mouse_event.x, mouse_event.y))); |
| 232 web_view->handleInputEvent(mouse_event); |
| 233 return true; |
| 234 } |
| 235 |
109 #if !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) | 236 #if !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) |
110 void AutomationRendererHelper::OnHeapProfilerDump(const std::string& reason) { | 237 void AutomationRendererHelper::OnHeapProfilerDump(const std::string& reason) { |
111 if (!::IsHeapProfilerRunning()) { | 238 if (!::IsHeapProfilerRunning()) { |
112 return; | 239 return; |
113 } | 240 } |
114 ::HeapProfilerDump(reason.c_str()); | 241 ::HeapProfilerDump(reason.c_str()); |
115 } | 242 } |
116 #endif // !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) | 243 #endif // !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) |
117 | 244 |
118 bool AutomationRendererHelper::OnMessageReceived(const IPC::Message& message) { | 245 bool AutomationRendererHelper::OnMessageReceived(const IPC::Message& message) { |
119 bool handled = true; | 246 bool handled = true; |
120 bool deserialize_success = true; | 247 bool deserialize_success = true; |
121 IPC_BEGIN_MESSAGE_MAP_EX(AutomationRendererHelper, message, | 248 IPC_BEGIN_MESSAGE_MAP_EX(AutomationRendererHelper, message, |
122 deserialize_success) | 249 deserialize_success) |
123 IPC_MESSAGE_HANDLER(AutomationMsg_SnapshotEntirePage, OnSnapshotEntirePage) | 250 IPC_MESSAGE_HANDLER(AutomationMsg_SnapshotEntirePage, OnSnapshotEntirePage) |
124 #if !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) | 251 #if !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) |
125 IPC_MESSAGE_HANDLER(AutomationMsg_HeapProfilerDump, OnHeapProfilerDump) | 252 IPC_MESSAGE_HANDLER(AutomationMsg_HeapProfilerDump, OnHeapProfilerDump) |
126 #endif // !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) | 253 #endif // !defined(NO_TCMALLOC) && (defined(OS_LINUX) || defined(OS_CHROMEOS)) |
| 254 IPC_MESSAGE_HANDLER(AutomationMsg_ProcessMouseEvent, OnProcessMouseEvent) |
127 IPC_MESSAGE_UNHANDLED(handled = false) | 255 IPC_MESSAGE_UNHANDLED(handled = false) |
128 IPC_END_MESSAGE_MAP_EX() | 256 IPC_END_MESSAGE_MAP_EX() |
129 if (!deserialize_success) { | 257 if (!deserialize_success) { |
130 LOG(ERROR) << "Failed to deserialize an IPC message"; | 258 LOG(ERROR) << "Failed to deserialize an IPC message"; |
131 } | 259 } |
132 return handled; | 260 return handled; |
133 } | 261 } |
134 | 262 |
135 void AutomationRendererHelper::WillPerformClientRedirect( | 263 void AutomationRendererHelper::WillPerformClientRedirect( |
136 WebFrame* frame, const WebURL& from, const WebURL& to, double interval, | 264 WebFrame* frame, const WebURL& from, const WebURL& to, double interval, |
137 double fire_time) { | 265 double fire_time) { |
138 Send(new AutomationMsg_WillPerformClientRedirect( | 266 Send(new AutomationMsg_WillPerformClientRedirect( |
139 routing_id(), frame->identifier(), interval)); | 267 routing_id(), frame->identifier(), interval)); |
140 } | 268 } |
141 | 269 |
142 void AutomationRendererHelper::DidCancelClientRedirect(WebFrame* frame) { | 270 void AutomationRendererHelper::DidCancelClientRedirect(WebFrame* frame) { |
143 Send(new AutomationMsg_DidCompleteOrCancelClientRedirect( | 271 Send(new AutomationMsg_DidCompleteOrCancelClientRedirect( |
144 routing_id(), frame->identifier())); | 272 routing_id(), frame->identifier())); |
145 } | 273 } |
146 | 274 |
147 void AutomationRendererHelper::DidCompleteClientRedirect( | 275 void AutomationRendererHelper::DidCompleteClientRedirect( |
148 WebFrame* frame, const WebURL& from) { | 276 WebFrame* frame, const WebURL& from) { |
149 Send(new AutomationMsg_DidCompleteOrCancelClientRedirect( | 277 Send(new AutomationMsg_DidCompleteOrCancelClientRedirect( |
150 routing_id(), frame->identifier())); | 278 routing_id(), frame->identifier())); |
151 } | 279 } |
| 280 |
| 281 void AutomationRendererHelper::OnProcessMouseEvent( |
| 282 const AutomationMouseEvent& event) { |
| 283 std::string error_msg; |
| 284 bool success = ProcessMouseEvent(event, &error_msg); |
| 285 Send(new AutomationMsg_ProcessMouseEventACK( |
| 286 routing_id(), success, error_msg)); |
| 287 } |
OLD | NEW |