| Index: components/web_view/test_runner/test_runner_application_delegate.cc
 | 
| diff --git a/components/web_view/test_runner/test_runner_application_delegate.cc b/components/web_view/test_runner/test_runner_application_delegate.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..ca8cb45241caf5e3946a356b3aae799584e75d8c
 | 
| --- /dev/null
 | 
| +++ b/components/web_view/test_runner/test_runner_application_delegate.cc
 | 
| @@ -0,0 +1,250 @@
 | 
| +// 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 "components/web_view/test_runner/test_runner_application_delegate.h"
 | 
| +
 | 
| +#include <iostream>
 | 
| +
 | 
| +#include "base/bind.h"
 | 
| +#include "base/command_line.h"
 | 
| +#include "base/files/file_path.h"
 | 
| +#include "base/files/file_util.h"
 | 
| +#include "base/files/scoped_temp_dir.h"
 | 
| +#include "base/location.h"
 | 
| +#include "base/path_service.h"
 | 
| +#include "base/thread_task_runner_handle.h"
 | 
| +#include "base/threading/thread_restrictions.h"
 | 
| +#include "components/view_manager/public/cpp/scoped_view_ptr.h"
 | 
| +#include "components/view_manager/public/cpp/view.h"
 | 
| +#include "components/view_manager/public/cpp/view_tree_connection.h"
 | 
| +#include "components/view_manager/public/cpp/view_tree_host_factory.h"
 | 
| +#include "mojo/application/public/cpp/application_connection.h"
 | 
| +#include "mojo/application/public/cpp/application_impl.h"
 | 
| +#include "mojo/converters/geometry/geometry_type_converters.h"
 | 
| +#include "mojo/services/network/public/interfaces/url_loader.mojom.h"
 | 
| +#include "net/base/filename_util.h"
 | 
| +#include "ui/gfx/geometry/rect.h"
 | 
| +#include "ui/gfx/geometry/size.h"
 | 
| +#include "url/gurl.h"
 | 
| +
 | 
| +#if defined(OS_WIN)
 | 
| +#include "base/strings/sys_string_conversions.h"
 | 
| +#include "base/strings/utf_string_conversions.h"
 | 
| +#endif
 | 
| +
 | 
| +namespace web_view {
 | 
| +
 | 
| +namespace {
 | 
| +
 | 
| +GURL GetURLForLayoutTest(const std::string& test_name,
 | 
| +                         base::FilePath* current_working_directory,
 | 
| +                         bool* enable_pixel_dumping,
 | 
| +                         std::string* expected_pixel_hash) {
 | 
| +  // A test name is formated like file:///path/to/test'--pixel-test'pixelhash
 | 
| +  std::string path_or_url = test_name;
 | 
| +  std::string pixel_switch;
 | 
| +  std::string pixel_hash;
 | 
| +  std::string::size_type separator_position = path_or_url.find('\'');
 | 
| +  if (separator_position != std::string::npos) {
 | 
| +    pixel_switch = path_or_url.substr(separator_position + 1);
 | 
| +    path_or_url.erase(separator_position);
 | 
| +  }
 | 
| +  separator_position = pixel_switch.find('\'');
 | 
| +  if (separator_position != std::string::npos) {
 | 
| +    pixel_hash = pixel_switch.substr(separator_position + 1);
 | 
| +    pixel_switch.erase(separator_position);
 | 
| +  }
 | 
| +  if (enable_pixel_dumping) {
 | 
| +    *enable_pixel_dumping =
 | 
| +        (pixel_switch == "--pixel-test" || pixel_switch == "-p");
 | 
| +  }
 | 
| +  if (expected_pixel_hash)
 | 
| +    *expected_pixel_hash = pixel_hash;
 | 
| +
 | 
| +  GURL test_url(path_or_url);
 | 
| +  if (!(test_url.is_valid() && test_url.has_scheme())) {
 | 
| +    // This is a test.
 | 
| +    base::ThreadRestrictions::ScopedAllowIO allow_io;
 | 
| +#if defined(OS_WIN)
 | 
| +    base::FilePath::StringType wide_path_or_url =
 | 
| +        base::SysNativeMBToWide(path_or_url);
 | 
| +    base::FilePath local_file(wide_path_or_url);
 | 
| +#else
 | 
| +    base::FilePath local_file(path_or_url);
 | 
| +#endif
 | 
| +    if (!base::PathExists(local_file)) {
 | 
| +      base::FilePath base_path;
 | 
| +      PathService::Get(base::DIR_SOURCE_ROOT, &base_path);
 | 
| +      local_file = base_path.Append(FILE_PATH_LITERAL("third_party"))
 | 
| +                       .Append(FILE_PATH_LITERAL("WebKit"))
 | 
| +                       .Append(FILE_PATH_LITERAL("LayoutTests"))
 | 
| +                       .Append(local_file);
 | 
| +    }
 | 
| +    test_url = net::FilePathToFileURL(base::MakeAbsoluteFilePath(local_file));
 | 
| +  }
 | 
| +  base::FilePath local_path;
 | 
| +  if (current_working_directory) {
 | 
| +    // We're outside of the message loop here, and this is a test.
 | 
| +    base::ThreadRestrictions::ScopedAllowIO allow_io;
 | 
| +    if (net::FileURLToFilePath(test_url, &local_path))
 | 
| +      *current_working_directory = local_path.DirName();
 | 
| +    else
 | 
| +      base::GetCurrentDirectory(current_working_directory);
 | 
| +  }
 | 
| +  return test_url;
 | 
| +}
 | 
| +
 | 
| +bool GetNextTestURL(const base::CommandLine::StringVector& args,
 | 
| +                    size_t* position,
 | 
| +                    GURL* test_url) {
 | 
| +  std::string test_string;
 | 
| +  if (*position >= args.size())
 | 
| +    return false;
 | 
| +  if (args[*position] == FILE_PATH_LITERAL("-")) {
 | 
| +    do {
 | 
| +      bool success = !!std::getline(std::cin, test_string, '\n');
 | 
| +      if (!success)
 | 
| +        return false;
 | 
| +    } while (test_string.empty());
 | 
| +  } else {
 | 
| +#if defined(OS_WIN)
 | 
| +    test_string = base::WideToUTF8(args[(*position)++]);
 | 
| +#else
 | 
| +    test_string = args[(*position)++];
 | 
| +#endif
 | 
| +  }
 | 
| +
 | 
| +  DCHECK(!test_string.empty());
 | 
| +  if (test_string == "QUIT")
 | 
| +    return false;
 | 
| +  bool enable_pixel_dumps;
 | 
| +  std::string pixel_hash;
 | 
| +  base::FilePath cwd;
 | 
| +  *test_url =
 | 
| +      GetURLForLayoutTest(test_string, &cwd, &enable_pixel_dumps, &pixel_hash);
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +TestRunnerApplicationDelegate::TestRunnerApplicationDelegate()
 | 
| +    : app_(nullptr),
 | 
| +      root_(nullptr),
 | 
| +      content_(nullptr),
 | 
| +      cmdline_position_(0u) {}
 | 
| +
 | 
| +TestRunnerApplicationDelegate::~TestRunnerApplicationDelegate() {
 | 
| +  if (root_)
 | 
| +    mojo::ScopedViewPtr::DeleteViewOrViewManager(root_);
 | 
| +}
 | 
| +
 | 
| +void TestRunnerApplicationDelegate::LaunchURL(const GURL& test_url) {
 | 
| +  if (!web_view_) {
 | 
| +    content_->SetAccessPolicy(mojo::ViewTree::ACCESS_POLICY_EMBED_ROOT);
 | 
| +    web_view_.reset(new WebView(this));
 | 
| +    web_view_->Init(app_, content_);
 | 
| +  }
 | 
| +  mojo::URLRequestPtr request(mojo::URLRequest::New());
 | 
| +  request->url = test_url.spec();
 | 
| +  web_view_->web_view()->LoadRequest(request.Pass());
 | 
| +}
 | 
| +
 | 
| +void TestRunnerApplicationDelegate::Terminate() {
 | 
| +  if (root_)
 | 
| +    mojo::ScopedViewPtr::DeleteViewOrViewManager(root_);
 | 
| +}
 | 
| +
 | 
| +////////////////////////////////////////////////////////////////////////////////
 | 
| +// mojo::ApplicationDelegate implementation:
 | 
| +
 | 
| +void TestRunnerApplicationDelegate::Initialize(mojo::ApplicationImpl* app) {
 | 
| +  app_ = app;
 | 
| +  mojo::CreateSingleViewTreeHost(app_, this, &host_);
 | 
| +}
 | 
| +
 | 
| +bool TestRunnerApplicationDelegate::ConfigureIncomingConnection(
 | 
| +    mojo::ApplicationConnection* connection) {
 | 
| +  connection->AddService<web_view::LayoutTestRunner>(this);
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +////////////////////////////////////////////////////////////////////////////////
 | 
| +// mojo::ViewTreeDelegate implementation:
 | 
| +
 | 
| +void TestRunnerApplicationDelegate::OnEmbed(mojo::View* root) {
 | 
| +  root_ = root;
 | 
| +
 | 
| +  // If this is a sys-check, then terminate in the next cycle.
 | 
| +  const char kCheckLayoutTestSysDeps[] = "check-layout-test-sys-deps";
 | 
| +  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
 | 
| +          kCheckLayoutTestSysDeps)) {
 | 
| +    base::ThreadTaskRunnerHandle::Get()->PostTask(
 | 
| +        FROM_HERE, base::Bind(&TestRunnerApplicationDelegate::Terminate,
 | 
| +                              base::Unretained(this)));
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  const gfx::Size kViewportSize(800, 600);
 | 
| +  host_->SetSize(mojo::Size::From(kViewportSize));
 | 
| +
 | 
| +  content_ = root_->connection()->CreateView();
 | 
| +  root_->AddChild(content_);
 | 
| +  content_->SetBounds(*mojo::Rect::From(gfx::Rect(kViewportSize)));
 | 
| +  content_->SetVisible(true);
 | 
| +
 | 
| +  cmdline_args_ = base::CommandLine::ForCurrentProcess()->GetArgs();
 | 
| +  std::cout << "#READY\n";
 | 
| +  std::cout.flush();
 | 
| +
 | 
| +  cmdline_position_ = 0;
 | 
| +  GURL test_url;
 | 
| +  if (GetNextTestURL(cmdline_args_, &cmdline_position_, &test_url))
 | 
| +    LaunchURL(test_url);
 | 
| +}
 | 
| +
 | 
| +void TestRunnerApplicationDelegate::OnConnectionLost(
 | 
| +    mojo::ViewTreeConnection* connection) {
 | 
| +  root_ = nullptr;
 | 
| +  app_->Quit();
 | 
| +}
 | 
| +
 | 
| +////////////////////////////////////////////////////////////////////////////////
 | 
| +// mojom::WebViewClient implementation:
 | 
| +
 | 
| +void TestRunnerApplicationDelegate::TopLevelNavigate(
 | 
| +    mojo::URLRequestPtr request) {
 | 
| +  web_view_->web_view()->LoadRequest(request.Pass());
 | 
| +}
 | 
| +
 | 
| +void TestRunnerApplicationDelegate::LoadingStateChanged(bool is_loading) {}
 | 
| +void TestRunnerApplicationDelegate::ProgressChanged(double progress) {}
 | 
| +void TestRunnerApplicationDelegate::TitleChanged(const mojo::String& title) {}
 | 
| +
 | 
| +////////////////////////////////////////////////////////////////////////////////
 | 
| +// LayoutTestRunner implementation:
 | 
| +
 | 
| +void TestRunnerApplicationDelegate::TestFinished() {
 | 
| +  std::cout << "#EOF\n";
 | 
| +  std::cout.flush();
 | 
| +
 | 
| +  std::cerr << "#EOF\n";
 | 
| +  std::cerr.flush();
 | 
| +
 | 
| +  GURL test_url;
 | 
| +  if (GetNextTestURL(cmdline_args_, &cmdline_position_, &test_url))
 | 
| +    LaunchURL(test_url);
 | 
| +  else
 | 
| +    Terminate();
 | 
| +}
 | 
| +
 | 
| +////////////////////////////////////////////////////////////////////////////////
 | 
| +// mojo::InterfaceFactory<LayoutTestRunner> implementation:
 | 
| +
 | 
| +void TestRunnerApplicationDelegate::Create(
 | 
| +    mojo::ApplicationConnection* connection,
 | 
| +    mojo::InterfaceRequest<web_view::LayoutTestRunner> request) {
 | 
| +  layout_test_runner_.AddBinding(this, request.Pass());
 | 
| +}
 | 
| +
 | 
| +}  // namespace web_view
 | 
| 
 |