diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-12 03:43:42 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-12 03:43:42 +0000 |
commit | 98fd5b2b2bd0a4db0e0372c014d5e50c17e8409a (patch) | |
tree | 33b8dc0437d21ecb93b0c2a9fca1736eac3b57a4 /mojo | |
parent | aee791a678ad3a51715b2c450216b083e3f93384 (diff) | |
download | chromium_src-98fd5b2b2bd0a4db0e0372c014d5e50c17e8409a.zip chromium_src-98fd5b2b2bd0a4db0e0372c014d5e50c17e8409a.tar.gz chromium_src-98fd5b2b2bd0a4db0e0372c014d5e50c17e8409a.tar.bz2 |
Introduce very beginning of navigation.
Add an interface to allow embedders to navigate embedded views.
This only supports local/pushState-style navigation right now.
BUG=
R=darin@chromium.org, davemoore@chromium.org, sky@chromium.org
Review URL: https://codereview.chromium.org/327523004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276521 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
-rw-r--r-- | mojo/examples/embedded_app/embedded_app.cc | 78 | ||||
-rw-r--r-- | mojo/examples/nesting_app/nesting_app.cc | 56 | ||||
-rw-r--r-- | mojo/examples/window_manager/window_manager.cc | 40 | ||||
-rw-r--r-- | mojo/mojo_examples.gypi | 5 | ||||
-rw-r--r-- | mojo/mojo_services.gypi | 14 | ||||
-rw-r--r-- | mojo/public/cpp/application/lib/service_connector.h | 2 | ||||
-rw-r--r-- | mojo/service_manager/service_manager_unittest.cc | 19 | ||||
-rw-r--r-- | mojo/services/navigation/navigation.mojom | 18 | ||||
-rw-r--r-- | mojo/shell/mojo_url_resolver.cc | 13 |
9 files changed, 205 insertions, 40 deletions
diff --git a/mojo/examples/embedded_app/embedded_app.cc b/mojo/examples/embedded_app/embedded_app.cc index adcef02..003cb82 100644 --- a/mojo/examples/embedded_app/embedded_app.cc +++ b/mojo/examples/embedded_app/embedded_app.cc @@ -4,8 +4,11 @@ #include "base/basictypes.h" #include "base/bind.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" #include "mojo/examples/window_manager/window_manager.mojom.h" #include "mojo/public/cpp/application/application.h" +#include "mojo/services/navigation/navigation.mojom.h" #include "mojo/services/public/cpp/view_manager/view.h" #include "mojo/services/public/cpp/view_manager/view_manager.h" #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" @@ -13,6 +16,8 @@ #include "mojo/services/public/cpp/view_manager/view_tree_node.h" #include "mojo/services/public/cpp/view_manager/view_tree_node_observer.h" #include "ui/events/event_constants.h" +#include "url/gurl.h" +#include "url/url_util.h" using mojo::view_manager::View; using mojo::view_manager::ViewManager; @@ -23,28 +28,54 @@ using mojo::view_manager::ViewTreeNodeObserver; namespace mojo { namespace examples { -namespace { - -const SkColor kColors[] = { SK_ColorYELLOW, - SK_ColorRED, - SK_ColorGREEN, - SK_ColorMAGENTA }; - -} // namespace class EmbeddedApp : public Application, public ViewManagerDelegate, public ViewObserver, public ViewTreeNodeObserver { public: - EmbeddedApp() {} + EmbeddedApp() : view_manager_(NULL) { + url::AddStandardScheme("mojo"); + } virtual ~EmbeddedApp() {} + void SetNodeColor(uint32 node_id, SkColor color) { + pending_node_colors_[node_id] = color; + ProcessPendingNodeColor(node_id); + } + private: + class Navigator : public InterfaceImpl<navigation::Navigator> { + public: + explicit Navigator(EmbeddedApp* app) : app_(app) {} + private: + virtual void Navigate(uint32 node_id, + navigation::NavigationDetailsPtr details) OVERRIDE { + GURL url(details->url.To<std::string>()); + if (!url.is_valid()) { + LOG(ERROR) << "URL is invalid."; + return; + } + // TODO(aa): Verify new URL is same origin as current origin. + SkColor color = 0x00; + if (!base::HexStringToUInt(url.path().substr(1), &color)) { + LOG(ERROR) << "Invalid URL, path not convertible to integer"; + return; + } + app_->SetNodeColor(node_id, color); + } + EmbeddedApp* app_; + DISALLOW_COPY_AND_ASSIGN(Navigator); + }; + // Overridden from Application: virtual void Initialize() MOJO_OVERRIDE { ViewManager::Create(this, this); + // TODO(aa): Weird for embeddee to talk to embedder by URL. Seems like + // embedder should be able to specify the SP embeddee receives, then + // communication can be anonymous. ConnectTo<IWindowManager>("mojo:mojo_window_manager", &window_manager_); + AddService<Navigator>(this); } // Overridden from ViewManagerDelegate: @@ -54,11 +85,14 @@ class EmbeddedApp : public Application, view->AddObserver(this); root->SetActiveView(view); root->AddObserver(this); - size_t index = view_manager->GetRoots().size() - 1; - view->SetColor(kColors[index % arraysize(kColors)]); + + roots_[root->id()] = root; + ProcessPendingNodeColor(root->id()); } virtual void OnRootRemoved(ViewManager* view_manager, ViewTreeNode* root) OVERRIDE { + roots_.erase(root->id()); + std::map<ViewTreeNode*, View*>::const_iterator it = views_to_reap_.find(root); if (it != views_to_reap_.end()) @@ -81,9 +115,31 @@ class EmbeddedApp : public Application, views_to_reap_[node] = old_view; } + void ProcessPendingNodeColor(uint32 node_id) { + RootMap::iterator root = roots_.find(node_id); + if (root == roots_.end()) + return; + + PendingNodeColors::iterator color = pending_node_colors_.find(node_id); + if (color == pending_node_colors_.end()) + return; + + root->second->active_view()->SetColor(color->second); + pending_node_colors_.erase(color); + } + + + view_manager::ViewManager* view_manager_; IWindowManagerPtr window_manager_; std::map<ViewTreeNode*, View*> views_to_reap_; + typedef std::map<uint32, ViewTreeNode*> RootMap; + RootMap roots_; + + // We can receive navigations for nodes we don't have yet. + typedef std::map<uint32, SkColor> PendingNodeColors; + PendingNodeColors pending_node_colors_; + DISALLOW_COPY_AND_ASSIGN(EmbeddedApp); }; diff --git a/mojo/examples/nesting_app/nesting_app.cc b/mojo/examples/nesting_app/nesting_app.cc index 249cc37..b882f4a 100644 --- a/mojo/examples/nesting_app/nesting_app.cc +++ b/mojo/examples/nesting_app/nesting_app.cc @@ -4,8 +4,10 @@ #include "base/basictypes.h" #include "base/bind.h" +#include "base/strings/stringprintf.h" #include "mojo/examples/window_manager/window_manager.mojom.h" #include "mojo/public/cpp/application/application.h" +#include "mojo/services/navigation/navigation.mojom.h" #include "mojo/services/public/cpp/view_manager/view.h" #include "mojo/services/public/cpp/view_manager/view_manager.h" #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" @@ -13,6 +15,7 @@ #include "mojo/services/public/cpp/view_manager/view_tree_node.h" #include "mojo/services/public/cpp/view_manager/view_tree_node_observer.h" #include "ui/events/event_constants.h" +#include "url/gurl.h" using mojo::view_manager::View; using mojo::view_manager::ViewManager; @@ -24,19 +27,42 @@ using mojo::view_manager::ViewTreeNodeObserver; namespace mojo { namespace examples { +namespace { +const char kEmbeddedAppURL[] = "mojo:mojo_embedded_app"; +} + // An app that embeds another app. class NestingApp : public Application, public ViewManagerDelegate, public ViewObserver { public: - NestingApp() {} + NestingApp() : nested_(NULL) {} virtual ~NestingApp() {} private: + class Navigator : public InterfaceImpl<navigation::Navigator> { + public: + explicit Navigator(NestingApp* app) : app_(app) {} + private: + virtual void Navigate(uint32 node_id, + navigation::NavigationDetailsPtr details) OVERRIDE { + GURL url(details->url.To<std::string>()); + if (!url.is_valid()) { + LOG(ERROR) << "URL is invalid."; + return; + } + app_->color_ = url.path().substr(1); + app_->NavigateChild(); + } + NestingApp* app_; + DISALLOW_COPY_AND_ASSIGN(Navigator); + }; + // Overridden from Application: virtual void Initialize() MOJO_OVERRIDE { ViewManager::Create(this, this); ConnectTo<IWindowManager>("mojo:mojo_window_manager", &window_manager_); + AddService<Navigator>(this); } // Overridden from ViewManagerDelegate: @@ -47,14 +73,21 @@ class NestingApp : public Application, view->SetColor(SK_ColorCYAN); view->AddObserver(this); - ViewTreeNode* nested = ViewTreeNode::Create(view_manager); - root->AddChild(nested); - nested->SetBounds(gfx::Rect(20, 20, 50, 50)); - nested->Embed("mojo:mojo_embedded_app"); + nested_ = ViewTreeNode::Create(view_manager); + root->AddChild(nested_); + nested_->SetBounds(gfx::Rect(20, 20, 50, 50)); + nested_->Embed(kEmbeddedAppURL); + + if (!navigator_.get()) + ConnectTo(kEmbeddedAppURL, &navigator_); + + NavigateChild(); } + virtual void OnRootRemoved(ViewManager* view_manager, ViewTreeNode* root) OVERRIDE { // TODO(beng): reap views & child nodes. + nested_ = NULL; } // Overridden from ViewObserver: @@ -63,6 +96,19 @@ class NestingApp : public Application, window_manager_->CloseWindow(view->node()->id()); } + void NavigateChild() { + if (!color_.empty() && nested_) { + navigation::NavigationDetailsPtr details( + navigation::NavigationDetails::New()); + details->url = + base::StringPrintf("%s/%s", kEmbeddedAppURL, color_.c_str()); + navigator_->Navigate(nested_->id(), details.Pass()); + } + } + + std::string color_; + ViewTreeNode* nested_; + navigation::NavigatorPtr navigator_; IWindowManagerPtr window_manager_; DISALLOW_COPY_AND_ASSIGN(NestingApp); diff --git a/mojo/examples/window_manager/window_manager.cc b/mojo/examples/window_manager/window_manager.cc index d998f0c..e9a561e 100644 --- a/mojo/examples/window_manager/window_manager.cc +++ b/mojo/examples/window_manager/window_manager.cc @@ -4,8 +4,10 @@ #include "base/basictypes.h" #include "base/bind.h" +#include "base/strings/stringprintf.h" #include "mojo/examples/window_manager/window_manager.mojom.h" #include "mojo/public/cpp/application/application.h" +#include "mojo/services/navigation/navigation.mojom.h" #include "mojo/services/public/cpp/view_manager/view.h" #include "mojo/services/public/cpp/view_manager/view_manager.h" #include "mojo/services/public/cpp/view_manager/view_manager_delegate.h" @@ -30,6 +32,19 @@ namespace examples { class WindowManager; +namespace { + +const SkColor kColors[] = { SK_ColorYELLOW, + SK_ColorRED, + SK_ColorGREEN, + SK_ColorMAGENTA }; + +const char kEmbeddedAppURL[] = "mojo:mojo_embedded_app"; +const char kNestingAppURL[] = "mojo:mojo_nesting_app"; +const char kMojoBrowserURL[] = "mojo:mojo_browser"; + +} // namespace + class WindowManagerConnection : public InterfaceImpl<IWindowManager> { public: explicit WindowManagerConnection(WindowManager* window_manager) @@ -69,11 +84,11 @@ class WindowManager : public Application, virtual void OnViewInputEvent(View* view, const EventPtr& event) OVERRIDE { if (event->action == ui::ET_MOUSE_RELEASED) { if (event->flags & ui::EF_LEFT_MOUSE_BUTTON) - CreateWindow("mojo:mojo_embedded_app"); + CreateWindow(kEmbeddedAppURL); else if (event->flags & ui::EF_RIGHT_MOUSE_BUTTON) - CreateWindow("mojo:mojo_nesting_app"); + CreateWindow(kNestingAppURL); else if (event->flags & ui::EF_MIDDLE_MOUSE_BUTTON) - CreateWindow("mojo:mojo_browser"); + CreateWindow(kMojoBrowserURL); } } @@ -94,7 +109,7 @@ class WindowManager : public Application, view->AddObserver(this); } - void CreateWindow(const String& url) { + void CreateWindow(const std::string& url) { ViewTreeNode* node = view_manager_->GetNodeById(parent_node_id_); gfx::Rect bounds(50, 50, 200, 200); @@ -108,6 +123,23 @@ class WindowManager : public Application, node->AddChild(embedded); embedded->SetBounds(bounds); embedded->Embed(url); + + // TODO(aa): Is there a way to ask for an interface and test whether it + // succeeded? That would be nicer than hard-coding the URLs that are known + // to support navigation. + if (url == kEmbeddedAppURL || url == kNestingAppURL) { + // TODO(aa): This means that there can only ever be one instance of every + // app, which seems wrong. Instead, perhaps embedder should get back a + // service provider that allows it to talk to embeddee. + navigation::NavigatorPtr navigator; + ConnectTo(url, &navigator); + navigation::NavigationDetailsPtr details( + navigation::NavigationDetails::New()); + size_t index = node->children().size() - 1; + details->url = base::StringPrintf( + "%s/%x", kEmbeddedAppURL, kColors[index % arraysize(kColors)]); + navigator->Navigate(embedded->id(), details.Pass()); + } } ViewManager* view_manager_; diff --git a/mojo/mojo_examples.gypi b/mojo/mojo_examples.gypi index a770a40..ad96198 100644 --- a/mojo/mojo_examples.gypi +++ b/mojo/mojo_examples.gypi @@ -320,6 +320,7 @@ 'mojo_environment_chromium', 'mojo_geometry_bindings', 'mojo_gles2', + 'mojo_navigation_bindings', 'mojo_view_manager_lib', 'mojo_window_manager_bindings', 'mojo_system_impl', @@ -337,11 +338,13 @@ '../base/base.gyp:base', '../ui/gfx/gfx.gyp:gfx_geometry', '../ui/gl/gl.gyp:gl', + '../url/url.gyp:url_lib', 'mojo_application', 'mojo_cpp_bindings', 'mojo_environment_chromium', 'mojo_geometry_bindings', 'mojo_gles2', + 'mojo_navigation_bindings', 'mojo_view_manager_lib', 'mojo_window_manager_bindings', 'mojo_system_impl', @@ -359,11 +362,13 @@ '../base/base.gyp:base', '../ui/gfx/gfx.gyp:gfx_geometry', '../ui/gl/gl.gyp:gl', + '../url/url.gyp:url_lib', 'mojo_application', 'mojo_cpp_bindings', 'mojo_environment_chromium', 'mojo_geometry_bindings', 'mojo_gles2', + 'mojo_navigation_bindings', 'mojo_view_manager_lib', 'mojo_window_manager_bindings', 'mojo_system_impl', diff --git a/mojo/mojo_services.gypi b/mojo/mojo_services.gypi index a8a5d15..1768ccf8 100644 --- a/mojo/mojo_services.gypi +++ b/mojo/mojo_services.gypi @@ -183,6 +183,20 @@ ], }, { + 'target_name': 'mojo_navigation_bindings', + 'type': 'static_library', + 'sources': [ + 'services/navigation/navigation.mojom', + ], + 'includes': [ 'public/tools/bindings/mojom_bindings_generator.gypi' ], + 'export_dependent_settings': [ + 'mojo_cpp_bindings', + ], + 'dependencies': [ + 'mojo_cpp_bindings', + ], + }, + { 'target_name': 'mojo_network_bindings', 'type': 'static_library', 'sources': [ diff --git a/mojo/public/cpp/application/lib/service_connector.h b/mojo/public/cpp/application/lib/service_connector.h index 914b2a9..b52140b 100644 --- a/mojo/public/cpp/application/lib/service_connector.h +++ b/mojo/public/cpp/application/lib/service_connector.h @@ -123,8 +123,6 @@ class ServiceConnector : public internal::ServiceConnectorBase { if (*it == impl) { delete impl; connections_.erase(it); - if (connections_.empty()) - owner_->RemoveServiceConnector(this); return; } } diff --git a/mojo/service_manager/service_manager_unittest.cc b/mojo/service_manager/service_manager_unittest.cc index 0161a80..429b707 100644 --- a/mojo/service_manager/service_manager_unittest.cc +++ b/mojo/service_manager/service_manager_unittest.cc @@ -35,6 +35,10 @@ class TestServiceImpl : public InterfaceImpl<TestService> { --context_->num_impls; } + virtual void OnConnectionError() OVERRIDE { + base::MessageLoop::current()->Quit(); + } + // TestService implementation: virtual void Test(const String& test_string) OVERRIDE { context_->last_test_string = test_string; @@ -75,8 +79,7 @@ class TestServiceLoader : public ServiceLoader { public: TestServiceLoader() : context_(NULL), - num_loads_(0), - quit_after_error_(false) { + num_loads_(0) { } virtual ~TestServiceLoader() { @@ -86,10 +89,6 @@ class TestServiceLoader : public ServiceLoader { } void set_context(TestContext* context) { context_ = context; } - void set_quit_after_error(bool quit_after_error) { - quit_after_error_ = quit_after_error; - } - int num_loads() const { return num_loads_; } private: @@ -104,16 +103,11 @@ class TestServiceLoader : public ServiceLoader { virtual void OnServiceError(ServiceManager* manager, const GURL& url) OVERRIDE { - if (quit_after_error_) { - base::MessageLoop::current()->PostTask(FROM_HERE, - base::MessageLoop::QuitClosure()); - } } scoped_ptr<Application> test_app_; TestContext* context_; int num_loads_; - bool quit_after_error_; DISALLOW_COPY_AND_ASSIGN(TestServiceLoader); }; @@ -223,7 +217,6 @@ class ServiceManagerTest : public testing::Test { TestServiceLoader* default_loader = new TestServiceLoader; default_loader->set_context(&context_); - default_loader->set_quit_after_error(true); service_manager_->set_default_loader( scoped_ptr<ServiceLoader>(default_loader)); @@ -264,7 +257,7 @@ TEST_F(ServiceManagerTest, ClientError) { test_client_.reset(NULL); loop_.Run(); EXPECT_EQ(0, context_.num_impls); - EXPECT_FALSE(HasFactoryForTestURL()); + EXPECT_TRUE(HasFactoryForTestURL()); } TEST_F(ServiceManagerTest, Deletes) { diff --git a/mojo/services/navigation/navigation.mojom b/mojo/services/navigation/navigation.mojom new file mode 100644 index 0000000..f9039d6 --- /dev/null +++ b/mojo/services/navigation/navigation.mojom @@ -0,0 +1,18 @@ +// Copyright 2014 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. + +module mojo.navigation { + +struct NavigationDetails { + string url; + // TODO(aa): method, data, etc. +}; + +// Applications implement this interface to support navigation of their views +// by embedders. +interface Navigator { + Navigate(uint32 node_id, NavigationDetails details); +}; + +} diff --git a/mojo/shell/mojo_url_resolver.cc b/mojo/shell/mojo_url_resolver.cc index 63a8b57..9591b1d 100644 --- a/mojo/shell/mojo_url_resolver.cc +++ b/mojo/shell/mojo_url_resolver.cc @@ -9,18 +9,19 @@ #include "base/logging.h" #include "base/path_service.h" #include "net/base/filename_util.h" +#include "url/url_util.h" namespace mojo { namespace shell { namespace { -std::string MakeSharedLibraryName(const std::string& file_name) { +std::string MakeSharedLibraryName(const std::string& host_name) { #if defined(OS_WIN) - return file_name + ".dll"; + return host_name + ".dll"; #elif defined(OS_LINUX) - return "lib" + file_name + ".so"; + return "lib" + host_name + ".so"; #elif defined(OS_MACOSX) - return "lib" + file_name + ".dylib"; + return "lib" + host_name + ".dylib"; #else NOTREACHED() << "dynamic loading of services not supported"; return std::string(); @@ -30,6 +31,8 @@ std::string MakeSharedLibraryName(const std::string& file_name) { } // namespace MojoURLResolver::MojoURLResolver() { + // Needed to treat first component of mojo URLs as host, not path. + url::AddStandardScheme("mojo"); } MojoURLResolver::~MojoURLResolver() { @@ -49,7 +52,7 @@ GURL MojoURLResolver::Resolve(const GURL& mojo_url) const { if (it != url_map_.end()) return it->second; - std::string lib = MakeSharedLibraryName(mojo_url.ExtractFileName()); + std::string lib = MakeSharedLibraryName(mojo_url.host()); if (local_file_set_.find(mojo_url) != local_file_set_.end()) { // Resolve to a local file URL. |