Index: headless/app/headless_browser_main.cc |
diff --git a/headless/app/headless_browser_main.cc b/headless/app/headless_browser_main.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..209d1735cd86d5d15d37e13e50a6aab6d185a01e |
--- /dev/null |
+++ b/headless/app/headless_browser_main.cc |
@@ -0,0 +1,191 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "headless/app/headless_browser_main.h" |
+ |
+#include "base/thread_task_runner_handle.h" |
+#include "content/public/browser/render_frame_host.h" |
+#include "content/public/browser/browser_main_runner.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/renderer/render_frame.h" |
+#include "content/shell/browser/shell.h" |
+#include "content/shell/browser/shell_browser_context.h" |
+#include "content/shell/browser/shell_content_browser_client.h" |
+#include "url/gurl.h" |
+ |
+#include "base/json/json_writer.h" |
+ |
+#include "third_party/WebKit/public/web/WebLocalFrame.h" |
+#include "third_party/WebKit/public/web/WebNodeList.h" |
+#include "third_party/WebKit/public/web/WebDocument.h" |
+#include "base/threading/thread.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "third_party/WebKit/public/platform/WebThread.h" |
+#include "third_party/WebKit/public/platform/Platform.h" |
+#include "third_party/WebKit/public/platform/WebTraceLocation.h" |
+#include "third_party/WebKit/public/platform/WebTaskRunner.h" |
+#include "third_party/WebKit/public/web/WebElement.h" |
+#include "base/command_line.h" |
+ |
+#include <iostream> |
+#include <fstream> |
+ |
+class Task : public blink::WebTaskRunner::Task { |
+ public: |
+ Task(std::function<void(void)> function_to_run): function_to_run_(function_to_run) { }; |
+ ~Task() { }; |
+ |
+ void run() override { |
+ function_to_run_(); |
+ } |
+ private: |
+ std::function<void(void)> function_to_run_; |
+}; |
+ |
+class Observer : public content::WebContentsObserver { |
+ public: |
+ Observer(content::WebContents* web_contents) |
+ : WebContentsObserver(web_contents), |
+ web_contents_(web_contents) |
+ { |
+ }; |
+ |
+ void DidStopLoading() override { |
+ DumpDOMTree(); |
+ } |
+ |
+ void DumpDOMTree() { |
+ content::RenderFrame* render_frame = |
+ content::RenderFrame::FromRoutingID(web_contents_->GetMainFrame()->GetRoutingID()); |
+ blink::WebFrame* web_frame = render_frame->GetWebFrame(); |
+ |
+ blink::Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, |
+ new Task([this, web_frame]() { |
+ auto dumped_tree = DumpNode(web_frame->document()); |
+ |
+ std::string dumped_string; |
+ base::JSONWriter::WriteWithOptions( |
+ *dumped_tree, |
+ base::JSONWriter::OPTIONS_PRETTY_PRINT, |
+ &dumped_string); |
+ |
+ std::cerr << dumped_string << std::endl; |
+ |
+ shutDownGraciously(); |
+ })); |
+ } |
+ |
+ static std::string NodeType(const blink::WebNode& node) { |
+ if (node.isLink()) { |
+ return "link"; |
+ } else if (node.isDocumentNode()) { |
+ return "document"; |
+ } else if (node.isCommentNode()) { |
+ return "comment"; |
+ } else if (node.isTextNode()) { |
+ return "text"; |
+ } else if (node.isElementNode()) { |
+ return "element"; |
+ } else { |
+ return "unknown"; |
+ } |
+ } |
+ |
+ static void DumpElementNode(const blink::WebElement& element, base::DictionaryValue* output) { |
+ output->SetString("tag", element.tagName()); |
+ |
+ output->Set("attributes", new base::DictionaryValue()); |
+ base::DictionaryValue* attributes; |
+ output->GetDictionary("attributes", &attributes); |
+ |
+ for (size_t i = 0; i < element.attributeCount(); ++i) { |
+ attributes->SetString( |
+ element.attributeLocalName(i).utf8(), |
+ element.attributeValue(i).utf8()); |
+ } |
+ } |
+ |
+ void DumpBoundingBox(const blink::WebNode& node, base::DictionaryValue* output) { |
+ output->Set("bounding_box", new base::DictionaryValue()); |
+ base::DictionaryValue* bounding_box; |
+ output->GetDictionary("bounding_box", &bounding_box); |
+ |
+ bounding_box->SetInteger("minX", node.boundingBox().minX); |
+ bounding_box->SetInteger("maxX", node.boundingBox().maxX); |
+ bounding_box->SetInteger("minY", node.boundingBox().minY); |
+ bounding_box->SetInteger("maxY", node.boundingBox().maxY); |
+ } |
+ |
+ scoped_ptr<base::DictionaryValue> DumpNode(const blink::WebNode& node) { |
+ scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); |
+ value->SetString("type", NodeType(node)); |
+ value->SetString("name", node.nodeName()); |
+ value->SetString("value", node.nodeValue()); |
+ |
+ DumpBoundingBox(node, value.get()); |
+ |
+ if (node.isElementNode()) { |
+ DumpElementNode(static_cast<const blink::WebElement&>(node), value.get()); |
+ } |
+ |
+ if (node.hasChildNodes()) { |
+ value->Set("children", new base::ListValue()); |
+ |
+ base::ListValue* children; |
+ value->GetList("children", &children); |
+ |
+ for (size_t i = 0; i < node.childNodes().length(); ++i) { |
+ children->Append(DumpNode(node.childNodes().item(i))); |
+ } |
+ } |
+ |
+ return value; |
+ } |
+ |
+ |
+ void shutDownGraciously() { |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::UI, FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); |
+ } |
+ private: |
+ content::WebContents* web_contents_; |
+}; |
+ |
+int HeadlessBrowserMain( |
+ const content::MainFunctionParams& parameters, |
+ const scoped_ptr<content::BrowserMainRunner>& main_runner) { |
+ int exit_code = main_runner->Initialize(parameters); |
+ |
+ DCHECK_LT(exit_code, 0) |
+ << "BrowserMainRunner::Initialize failed in HeadlessBrowserMain"; |
+ |
+ if (exit_code >= 0) |
+ return exit_code; |
+ |
+ content::Shell* main_window = content::Shell::CreateNewWindow( |
+ content::ShellContentBrowserClient::Get()->browser_context(), |
+ GURL(), |
+ NULL, |
+ gfx::Size(700, 700)); |
+ |
+ base::CommandLine::StringVector args = |
+ base::CommandLine::ForCurrentProcess()->GetArgs(); |
+ if (args.empty()) { |
+ std::cerr << "Provide url to open" << std::endl; |
+ return 666; |
+ } |
+ GURL url(args[0]); |
+ |
+ Observer observer(main_window->web_contents()); |
+ |
+ main_window->LoadURL(url); |
+ |
+ main_runner->Run(); |
+ |
+ main_runner->Shutdown(); |
+ |
+ return exit_code; |
+} |
+ |
+ |