| 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;
|
| +}
|
| +
|
| +
|
|
|