Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(575)

Side by Side Diff: headless/app/headless_shell.cc

Issue 1430673002: Headless demo (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Better javascript Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « headless/DEPS ('k') | headless/lib/browser/headless_browser_context.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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 <string>
6 #include <iostream>
7 #include <fstream>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/json/json_writer.h"
14 #include "base/location.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/stl_util.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "base/threading/thread.h"
20 #include "base/trace_event/trace_config.h"
21 #include "base/values.h"
22 #include "cc/output/copy_output_request.h"
23 #include "cc/output/copy_output_result.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/common/content_switches.h"
26 #include "headless/public/headless_browser.h"
27 #include "headless/public/web_contents.h"
28 #include "headless/public/web_document.h"
29 #include "headless/public/web_element.h"
30 #include "headless/public/web_frame.h"
31 #include "headless/public/web_node.h"
32 #include "third_party/WebKit/public/platform/WebRect.h"
33 #include "third_party/skia/include/core/SkBitmap.h"
34 #include "ui/gfx/codec/png_codec.h"
35
36 using headless::HeadlessBrowser;
37 using headless::WebContents;
38 using headless::WebElement;
39 using headless::WebNode;
40
41 void DoNothing() {}
42
43 void DumpElementNode(const WebElement& element,
44 base::DictionaryValue* output) {
45 output->SetString("tag", element.TagName());
46
47 if (!element.Attributes().empty()) {
48 base::DictionaryValue* attributes = new base::DictionaryValue();
49 output->Set("attributes", attributes);
50
51 for (const auto& attribute : element.Attributes()) {
52 attributes->SetString(attribute.first, attribute.second);
53 }
54 }
55 }
56
57 scoped_ptr<base::DictionaryValue> DumpNode(const WebNode& node) {
58 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
59 result->SetString("value", node.Value());
60
61 if (node.IsElement()) {
62 DumpElementNode(node.AsElement(), result.get());
63 }
64
65 if (node.HasChildNodes()) {
66 result->Set("children", new base::ListValue());
67
68 base::ListValue* children;
69 result->GetList("children", &children);
70
71 for (WebNode child = node.FirstChild();;
72 child = child.NextSibling()) {
73 children->Append(DumpNode(child));
74
75 if (child == node.LastChild()) {
76 break;
77 }
78 }
79 }
80
81 return result;
82 }
83
84 class Observer : public WebContents::Observer {
85 public:
86 Observer(HeadlessBrowser* browser,
87 WebContents* web_contents)
88 : WebContents::Observer(web_contents)
89 , browser_(browser)
90 , web_contents_(web_contents)
91 , screenshot_captured_(false, false)
92 , javascript_executed_(false, false)
93 , dom_dumped_(false, false)
94 , trace_recorded_(false, false) {}
95
96 ~Observer() override {}
97
98
99 void DumpDOMTree() {
100 scoped_ptr<headless::WebFrame> main_frame = web_contents_->main_frame();
101
102 scoped_ptr<base::DictionaryValue> dumped_tree = DumpNode(main_frame->documen t());
103
104 content::BrowserThread::PostTask(
105 content::BrowserThread::FILE,
106 FROM_HERE,
107 base::Bind(&Observer::WriteDOMToFile,
108 base::Unretained(this),
109 std::string("dom.json"),
110 base::Owned(dumped_tree.release())));
111 }
112
113 std::string JSONToString(base::Value* value) {
114 std::string string;
115 base::JSONWriter::WriteWithOptions(
116 *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &string);
117 return string;
118 }
119
120 void WriteDOMToFile(
121 const std::string& path,
122 base::Value* dumped_tree) {
123 std::string dumped_string = JSONToString(dumped_tree);
124
125 base::WriteFile(base::FilePath(path),
126 dumped_string.c_str(),
127 dumped_string.size());
128
129 dom_dumped_.Signal();
130 }
131
132 void GetScreenshot(scoped_ptr<SkBitmap> bitmap) {
133 content::BrowserThread::PostTask(
134 content::BrowserThread::FILE,
135 FROM_HERE,
136 base::Bind(&Observer::WriteScreenshot,
137 base::Unretained(this),
138 base::Owned(bitmap.release())));
139 }
140
141 void WriteScreenshot(SkBitmap* bitmap) {
142 std::vector<unsigned char> png_data;
143 gfx::PNGCodec::FastEncodeBGRASkBitmap(*bitmap, true, &png_data);
144 base::WriteFile(base::FilePath("screenshot.png"),
145 reinterpret_cast<const char*>(vector_as_array(&png_data)),
146 png_data.size());
147 screenshot_captured_.Signal();
148 }
149
150 void ProcessJavaScriptOutput(const std::vector<scoped_ptr<base::Value>>& value s) {
151 std::cerr << "Got " << values.size() << " values from javascript" << std::en dl;
152 for (auto& value : values) {
153 std::cerr << "JavaScript value: "
154 << (value ? JSONToString(value.get()) : "empty value") << std::e ndl;
155 }
156 javascript_executed_.Signal();
157 }
158
159 void ExecuteJavaScript() {
160 web_contents_->main_frame()->ExecuteScript("console.log('Written from JavaSc ript')");
161 web_contents_->main_frame()->ExecuteScriptAndReturnValue(
162 "[1, 2, {'a': 3, 'b': 'c'}]",
163 base::Bind(&Observer::ProcessJavaScriptOutput, base::Unretained(this)));
164 }
165
166 void MaybeShutdown() {
167 const base::CommandLine& command_line =
168 *base::CommandLine::ForCurrentProcess();
169 if (!command_line.HasSwitch(switches::kRemoteDebuggingPort))
170 browser_->Stop();
171 }
172
173 void StopShutdownThread() {
174 stop_browser_thread_->Stop();
175 }
176
177 void DidFinishTracing() {
178 trace_recorded_.Signal();
179 }
180
181 void WaitForTasksToComplete() {
182 screenshot_captured_.Wait();
183 javascript_executed_.Wait();
184 dom_dumped_.Wait();
185 trace_recorded_.Wait();
186
187 browser_->browser_main_thread()->PostTask(
188 FROM_HERE,
189 base::Bind(&Observer::MaybeShutdown, base::Unretained(this)));
190
191 content::BrowserThread::PostTask(
192 content::BrowserThread::PROCESS_LAUNCHER,
193 FROM_HERE,
194 base::Bind(&Observer::StopShutdownThread, base::Unretained(this)));
195 }
196
197
198 void DocumentOnLoadCompletedInMainFrame() override {
199 fprintf(stderr, "Loaded\n");
200 web_contents_->GetScreenshot(
201 base::Bind(&Observer::GetScreenshot, base::Unretained(this)));
202
203 browser_->renderer_main_thread()->PostTask(
204 FROM_HERE,
205 base::Bind(&Observer::ExecuteJavaScript, base::Unretained(this)));
206
207 browser_->renderer_main_thread()->PostTask(
208 FROM_HERE,
209 base::Bind(&Observer::DumpDOMTree, base::Unretained(this)));
210
211 browser_->StopTracing("chrometrace.log",
212 base::Bind(&Observer::DidFinishTracing,
213 base::Unretained(this)));
214
215 stop_browser_thread_.reset(new base::Thread("WaitForTasksAndStopBrowserThrea d"));
216 stop_browser_thread_->Start();
217
218 stop_browser_thread_->task_runner()->PostTask(
219 FROM_HERE,
220 base::Bind(&Observer::WaitForTasksToComplete, base::Unretained(this)));
221 }
222
223 private:
224 HeadlessBrowser* browser_;
225 WebContents* web_contents_;
226
227 scoped_ptr<base::Thread> stop_browser_thread_;
228
229 base::WaitableEvent screenshot_captured_;
230 base::WaitableEvent javascript_executed_;
231 base::WaitableEvent dom_dumped_;
232 base::WaitableEvent trace_recorded_;
233 };
234
235 void Start() {
236 HeadlessBrowser* browser = HeadlessBrowser::Get();
237
238 browser->StartTracing(
239 base::trace_event::TraceConfig("", ""),
240 base::Bind(&DoNothing));
241
242 static scoped_ptr<WebContents> web_contents = browser->CreateWebContents({800, 600});
243 static scoped_ptr<Observer> observer(
244 new Observer(browser, web_contents.get()));
245
246 base::CommandLine::StringVector args =
247 base::CommandLine::ForCurrentProcess()->GetArgs();
248
249 const std::string DEFAULT_URL = "https://google.com";
250
251 std::string url;
252 if (args.empty() || args[0].empty()) {
253 LOG(ERROR) << "No url provided, opening default one";
254 url = DEFAULT_URL;
255 } else {
256 url = args[0];
257 }
258 web_contents->OpenURL(GURL(url));
259 }
260
261 int main(int argc, const char** argv) {
262 HeadlessBrowser* browser = HeadlessBrowser::Get();
263
264 return browser->Run(
265 HeadlessBrowser::Options::Builder(argc, argv).Build(),
266 base::Bind(Start));
267 }
OLDNEW
« no previous file with comments | « headless/DEPS ('k') | headless/lib/browser/headless_browser_context.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698