summaryrefslogtreecommitdiffstats
path: root/blimp/engine
diff options
context:
space:
mode:
authordtrainor <dtrainor@chromium.org>2015-11-30 16:53:05 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-01 00:54:00 +0000
commit160f8eca573286f3bb369975ac2e9de63b0cc477 (patch)
tree3a416ada921c22f0f3902badd415af17ba73a73c /blimp/engine
parent7f3d85b096f66870a15b37c2f40b219b2e292693 (diff)
downloadchromium_src-160f8eca573286f3bb369975ac2e9de63b0cc477.zip
chromium_src-160f8eca573286f3bb369975ac2e9de63b0cc477.tar.gz
chromium_src-160f8eca573286f3bb369975ac2e9de63b0cc477.tar.bz2
Add glue between the client and engine for Blimp
- Add BlimpMessageProcessors to handle RENDER_WIDGET, INPUT, and COMPOSITOR message types to/from the client and engine. - Tie the message processors into BlimpCompositor on the client and BlimpEngineSession on the server. - Update BlimpView and BlimpCompositor to fix how we handle output surfaces and how we shut down and build the LayerTreeHost based on incoming RENDER_WIDGET and COMPOSITOR messages. BUG=550693 Review URL: https://codereview.chromium.org/1450423002 Cr-Commit-Position: refs/heads/master@{#362299}
Diffstat (limited to 'blimp/engine')
-rw-r--r--blimp/engine/BUILD.gn8
-rw-r--r--blimp/engine/DEPS1
-rw-r--r--blimp/engine/browser/BUILD.gn22
-rw-r--r--blimp/engine/browser/blimp_engine_session.cc72
-rw-r--r--blimp/engine/browser/blimp_engine_session.h30
-rw-r--r--blimp/engine/browser/engine_render_widget_message_processor.cc136
-rw-r--r--blimp/engine/browser/engine_render_widget_message_processor.h91
-rw-r--r--blimp/engine/browser/engine_render_widget_message_processor_unittest.cc208
8 files changed, 558 insertions, 10 deletions
diff --git a/blimp/engine/BUILD.gn b/blimp/engine/BUILD.gn
index bb6cddd..18399a9 100644
--- a/blimp/engine/BUILD.gn
+++ b/blimp/engine/BUILD.gn
@@ -44,6 +44,14 @@ repack("pak") {
output = "$root_out_dir/blimp_engine.pak"
}
+source_set("unit_tests") {
+ testonly = true
+
+ deps = [
+ "//blimp/engine/browser:unit_tests",
+ ]
+}
+
if (is_linux) {
executable("blimp_engine_app") {
sources = [
diff --git a/blimp/engine/DEPS b/blimp/engine/DEPS
index 5054124..b9a50e1 100644
--- a/blimp/engine/DEPS
+++ b/blimp/engine/DEPS
@@ -6,6 +6,7 @@ include_rules = [
"+content/public",
"+net",
"+third_party/khronos/GLES2/gl2.h",
+ "+third_party/WebKit/public/web/WebInputEvent.h",
"+ui/aura",
"+ui/base",
"+ui/compositor",
diff --git a/blimp/engine/browser/BUILD.gn b/blimp/engine/browser/BUILD.gn
index a4ce000..9524816 100644
--- a/blimp/engine/browser/BUILD.gn
+++ b/blimp/engine/browser/BUILD.gn
@@ -18,6 +18,8 @@ source_set("browser") {
"blimp_permission_manager.h",
"blimp_url_request_context_getter.cc",
"blimp_url_request_context_getter.h",
+ "engine_render_widget_message_processor.cc",
+ "engine_render_widget_message_processor.h",
]
deps = [
@@ -36,3 +38,23 @@ source_set("browser") {
"//ui/wm",
]
}
+
+source_set("unit_tests") {
+ testonly = true
+
+ sources = [
+ "engine_render_widget_message_processor_unittest.cc",
+ ]
+
+ deps = [
+ ":browser",
+ "//base",
+ "//base/test:run_all_unittests",
+ "//base/test:test_support",
+ "//blimp/common/proto",
+ "//blimp/engine/common",
+ "//blimp/net:blimp_net",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
diff --git a/blimp/engine/browser/blimp_engine_session.cc b/blimp/engine/browser/blimp_engine_session.cc
index d6784fc..c399d54 100644
--- a/blimp/engine/browser/blimp_engine_session.cc
+++ b/blimp/engine/browser/blimp_engine_session.cc
@@ -4,6 +4,7 @@
#include "blimp/engine/browser/blimp_engine_session.h"
+#include "base/lazy_instance.h"
#include "blimp/common/proto/blimp_message.pb.h"
#include "blimp/common/proto/control.pb.h"
#include "blimp/engine/browser/blimp_browser_context.h"
@@ -11,6 +12,8 @@
#include "blimp/engine/ui/blimp_screen.h"
#include "blimp/engine/ui/blimp_ui_context_factory.h"
#include "blimp/net/blimp_connection.h"
+#include "blimp/net/blimp_message_multiplexer.h"
+#include "blimp/net/null_blimp_message_processor.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
@@ -22,6 +25,7 @@
#include "ui/aura/env.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/wm/core/base_focus_rules.h"
#include "ui/wm/core/default_activation_client.h"
#include "ui/wm/core/focus_controller.h"
@@ -34,6 +38,11 @@ namespace blimp {
namespace engine {
namespace {
+const int kDummyTabId = 0;
+
+base::LazyInstance<blimp::NullBlimpMessageProcessor> g_blimp_message_processor =
+ LAZY_INSTANCE_INITIALIZER;
+
// Focus rules that support activating an child window.
class FocusRulesImpl : public wm::BaseFocusRules {
public:
@@ -52,9 +61,17 @@ class FocusRulesImpl : public wm::BaseFocusRules {
BlimpEngineSession::BlimpEngineSession(
scoped_ptr<BlimpBrowserContext> browser_context)
- : browser_context_(std::move(browser_context)), screen_(new BlimpScreen) {}
+ : browser_context_(std::move(browser_context)),
+ screen_(new BlimpScreen),
+ // TODO(dtrainor, haibinlu): Properly pull these from the BlimpMessageMux.
+ render_widget_processor_(g_blimp_message_processor.Pointer(),
+ g_blimp_message_processor.Pointer()) {
+ render_widget_processor_.SetDelegate(kDummyTabId, this);
+}
-BlimpEngineSession::~BlimpEngineSession() {}
+BlimpEngineSession::~BlimpEngineSession() {
+ render_widget_processor_.RemoveDelegate(kDummyTabId);
+}
void BlimpEngineSession::Initialize() {
DCHECK(!gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE));
@@ -102,6 +119,11 @@ void BlimpEngineSession::CloseWebContents(const int target_tab_id) {
web_contents_->Close();
}
+void BlimpEngineSession::HandleResize(const gfx::Size& size) {
+ // TODO(dtrainor, haibinlu): Set the proper size on the WebContents/save for
+ // future WebContents objects.
+}
+
void BlimpEngineSession::LoadUrl(const int target_tab_id, const GURL& url) {
if (url.is_empty() || !web_contents_)
return;
@@ -134,12 +156,35 @@ void BlimpEngineSession::Reload(const int target_tab_id) {
web_contents_->GetController().Reload(true);
}
+void BlimpEngineSession::OnWebInputEvent(
+ scoped_ptr<blink::WebInputEvent> event) {
+ if (!web_contents_ || !web_contents_->GetRenderViewHost())
+ return;
+
+ // TODO(dtrainor): Send the input event directly to the render process?
+}
+
+void BlimpEngineSession::OnCompositorMessageReceived(
+ const std::vector<uint8_t>& message) {
+ // Make sure that We actually have a valid WebContents and RenderViewHost.
+ if (!web_contents_ || !web_contents_->GetRenderViewHost())
+ return;
+
+ content::RenderWidgetHost* host =
+ web_contents_->GetRenderViewHost()->GetWidget();
+
+ // Make sure we actually have a valid RenderWidgetHost.
+ if (!host)
+ return;
+
+ host->HandleCompositorProto(message);
+}
+
void BlimpEngineSession::ProcessMessage(
scoped_ptr<BlimpMessage> message,
const net::CompletionCallback& callback) {
DCHECK(message->type() == BlimpMessage::CONTROL ||
- message->type() == BlimpMessage::NAVIGATION ||
- message->type() == BlimpMessage::COMPOSITOR);
+ message->type() == BlimpMessage::NAVIGATION);
if (message->type() == BlimpMessage::CONTROL) {
switch (message->control().type()) {
@@ -148,6 +193,10 @@ void BlimpEngineSession::ProcessMessage(
break;
case ControlMessage::CLOSE_TAB:
CloseWebContents(message->target_tab_id());
+ case ControlMessage::SIZE:
+ HandleResize(gfx::Size(message->control().resize().width(),
+ message->control().resize().height()));
+ break;
default:
NOTIMPLEMENTED();
}
@@ -226,8 +275,10 @@ void BlimpEngineSession::RequestToLockMouse(content::WebContents* web_contents,
}
void BlimpEngineSession::CloseContents(content::WebContents* source) {
- if (source == web_contents_.get())
+ if (source == web_contents_.get()) {
+ Observe(nullptr);
web_contents_.reset();
+ }
}
void BlimpEngineSession::ActivateContents(content::WebContents* contents) {
@@ -236,14 +287,19 @@ void BlimpEngineSession::ActivateContents(content::WebContents* contents) {
void BlimpEngineSession::ForwardCompositorProto(
const std::vector<uint8_t>& proto) {
- // Send the compositor proto over the network layer to the client, which will
- // apply the proto to their local compositor instance.
- // TODO(dtrainor): Send the compositor proto.
+ render_widget_processor_.SendCompositorMessage(kDummyTabId, proto);
+}
+
+void BlimpEngineSession::RenderViewHostChanged(
+ content::RenderViewHost* old_host,
+ content::RenderViewHost* new_host) {
+ render_widget_processor_.OnRenderWidgetInitialized(kDummyTabId);
}
void BlimpEngineSession::PlatformSetContents(
scoped_ptr<content::WebContents> new_contents) {
new_contents->SetDelegate(this);
+ Observe(new_contents.get());
web_contents_ = std::move(new_contents);
aura::Window* parent = window_tree_host_->window();
diff --git a/blimp/engine/browser/blimp_engine_session.h b/blimp/engine/browser/blimp_engine_session.h
index 6b117a9..4bba487 100644
--- a/blimp/engine/browser/blimp_engine_session.h
+++ b/blimp/engine/browser/blimp_engine_session.h
@@ -7,8 +7,10 @@
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "blimp/engine/browser/engine_render_widget_message_processor.h"
#include "blimp/net/blimp_message_processor.h"
#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
#include "net/base/completion_callback.h"
#include "ui/gfx/geometry/size.h"
@@ -23,9 +25,14 @@ class WindowTreeClient;
namespace content {
class BrowserContext;
+class RenderViewHost;
class WebContents;
}
+namespace gfx {
+class Size;
+}
+
namespace wm {
class FocusController;
}
@@ -43,8 +50,11 @@ class BlimpScreen;
class BlimpUiContextFactory;
class BlimpWindowTreeHost;
-class BlimpEngineSession : public BlimpMessageProcessor,
- public content::WebContentsDelegate {
+class BlimpEngineSession
+ : public BlimpMessageProcessor,
+ public content::WebContentsDelegate,
+ public content::WebContentsObserver,
+ public EngineRenderWidgetMessageProcessor::RenderWidgetMessageDelegate {
public:
explicit BlimpEngineSession(scoped_ptr<BlimpBrowserContext> browser_context);
~BlimpEngineSession() override;
@@ -63,6 +73,7 @@ class BlimpEngineSession : public BlimpMessageProcessor,
// Creates a new WebContents, which will be indexed by |target_tab_id|.
void CreateWebContents(const int target_tab_id);
void CloseWebContents(const int target_tab_id);
+ void HandleResize(const gfx::Size& size);
// NavigationMessage handler methods.
// Navigates the target tab to the |url|.
@@ -71,6 +82,12 @@ class BlimpEngineSession : public BlimpMessageProcessor,
void GoForward(const int target_tab_id);
void Reload(const int target_tab_id);
+ // RenderWidgetMessage handler methods.
+ // RenderWidgetMessageDelegate implementation.
+ void OnWebInputEvent(scoped_ptr<blink::WebInputEvent> event) override;
+ void OnCompositorMessageReceived(
+ const std::vector<uint8_t>& message) override;
+
// content::WebContentsDelegate implementation.
content::WebContents* OpenURLFromTab(
content::WebContents* source,
@@ -88,6 +105,10 @@ class BlimpEngineSession : public BlimpMessageProcessor,
void ActivateContents(content::WebContents* contents) override;
void ForwardCompositorProto(const std::vector<uint8_t>& proto) override;
+ // content::WebContentsObserver implementation.
+ void RenderViewHostChanged(content::RenderViewHost* old_host,
+ content::RenderViewHost* new_host) override;
+
// Sets up and owns |new_contents|.
void PlatformSetContents(scoped_ptr<content::WebContents> new_contents);
@@ -114,6 +135,11 @@ class BlimpEngineSession : public BlimpMessageProcessor,
// Currently attached client connection.
scoped_ptr<BlimpConnection> client_connection_;
+ // The bridge to the network layer that does the RenderWidget proto/id work.
+ // TODO(dtrainor, haibinlu): Move this to a higher level once we start dealing
+ // with multiple tabs.
+ EngineRenderWidgetMessageProcessor render_widget_processor_;
+
DISALLOW_COPY_AND_ASSIGN(BlimpEngineSession);
};
diff --git a/blimp/engine/browser/engine_render_widget_message_processor.cc b/blimp/engine/browser/engine_render_widget_message_processor.cc
new file mode 100644
index 0000000..00975d1
--- /dev/null
+++ b/blimp/engine/browser/engine_render_widget_message_processor.cc
@@ -0,0 +1,136 @@
+// 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 "blimp/engine/browser/engine_render_widget_message_processor.h"
+
+#include "base/numerics/safe_conversions.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/proto/compositor.pb.h"
+#include "blimp/common/proto/input.pb.h"
+#include "blimp/common/proto/render_widget.pb.h"
+#include "net/base/net_errors.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+namespace blimp {
+
+EngineRenderWidgetMessageProcessor::EngineRenderWidgetMessageProcessor(
+ BlimpMessageProcessor* render_widget_message_processor,
+ BlimpMessageProcessor* compositor_message_processor)
+ : render_widget_message_processor_(render_widget_message_processor),
+ compositor_message_processor_(compositor_message_processor) {
+ // TODO(dtrainor): Register as a BlimpMessageProcessor for
+ // BlimpMessage::INPUT and BlimpMessage::COMPOSITOR messages.
+}
+
+EngineRenderWidgetMessageProcessor::~EngineRenderWidgetMessageProcessor() {
+ // TODO(dtrainor): Unregister as a BlimpMessageProcessor for
+ // BlimpMessage::INPUT and BlimpMessage::COMPOSITOR messages.
+}
+
+void EngineRenderWidgetMessageProcessor::OnRenderWidgetInitialized(
+ const int tab_id) {
+ render_widget_ids_[tab_id] = GetRenderWidgetId(tab_id) + 1;
+
+ scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage);
+ blimp_message->set_target_tab_id(tab_id);
+
+ RenderWidgetMessage* render_widget_message =
+ blimp_message->mutable_render_widget();
+
+ render_widget_message->set_type(RenderWidgetMessage::INITIALIZE);
+ render_widget_message->set_render_widget_id(GetRenderWidgetId(tab_id));
+
+ render_widget_message_processor_->ProcessMessage(std::move(blimp_message),
+ net::CompletionCallback());
+}
+
+void EngineRenderWidgetMessageProcessor::SendCompositorMessage(
+ const int tab_id,
+ const std::vector<uint8_t>& message) {
+ scoped_ptr<BlimpMessage> blimp_message(new BlimpMessage);
+ blimp_message->set_target_tab_id(tab_id);
+
+ CompositorMessage* compositor_message = blimp_message->mutable_compositor();
+ uint32_t render_widget_id = GetRenderWidgetId(tab_id);
+ DCHECK_LT(0U, render_widget_id);
+ compositor_message->set_render_widget_id(render_widget_id);
+ // TODO(dtrainor): Move the transport medium to std::string* and use
+ // set_allocated_payload.
+ compositor_message->set_payload(message.data(),
+ base::checked_cast<int>(message.size()));
+
+ render_widget_message_processor_->ProcessMessage(std::move(blimp_message),
+ net::CompletionCallback());
+}
+
+void EngineRenderWidgetMessageProcessor::SetDelegate(
+ const int tab_id, RenderWidgetMessageDelegate* delegate) {
+ DCHECK(!FindDelegate(tab_id));
+ delegates_[tab_id] = delegate;
+}
+
+void EngineRenderWidgetMessageProcessor::RemoveDelegate(const int tab_id) {
+ DelegateMap::iterator it = delegates_.find(tab_id);
+ if (it != delegates_.end())
+ delegates_.erase(it);
+}
+
+void EngineRenderWidgetMessageProcessor::ProcessMessage(
+ scoped_ptr<BlimpMessage> message,
+ const net::CompletionCallback& callback) {
+ DCHECK(message->type() == BlimpMessage::INPUT ||
+ message->type() == BlimpMessage::COMPOSITOR);
+
+ int target_tab_id = message->target_tab_id();
+ uint32_t render_widget_id = GetRenderWidgetId(target_tab_id);
+ DCHECK_GT(render_widget_id, 0U);
+
+ RenderWidgetMessageDelegate* delegate = FindDelegate(target_tab_id);
+ DCHECK(delegate);
+
+ switch (message->type()) {
+ case BlimpMessage::INPUT:
+ if (message->input().render_widget_id() == render_widget_id) {
+ scoped_ptr<blink::WebInputEvent> event =
+ input_message_processor_.ProcessMessage(message->input());
+ if (event)
+ delegate->OnWebInputEvent(std::move(event));
+ }
+ break;
+ case BlimpMessage::COMPOSITOR:
+ if (message->compositor().render_widget_id() == render_widget_id) {
+ std::vector<uint8_t> payload(message->compositor().payload().size());
+ memcpy(payload.data(),
+ message->compositor().payload().data(),
+ payload.size());
+ delegate->OnCompositorMessageReceived(payload);
+ }
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ if (!callback.is_null()) {
+ callback.Run(net::OK);
+ }
+}
+
+EngineRenderWidgetMessageProcessor::RenderWidgetMessageDelegate*
+EngineRenderWidgetMessageProcessor::FindDelegate(
+ const int tab_id) {
+ DelegateMap::const_iterator it = delegates_.find(tab_id);
+ if (it != delegates_.end())
+ return it->second;
+ return nullptr;
+}
+
+uint32_t EngineRenderWidgetMessageProcessor::GetRenderWidgetId(
+ const int tab_id) {
+ RenderWidgetIdMap::const_iterator it = render_widget_ids_.find(tab_id);
+ if (it != render_widget_ids_.end())
+ return it->second;
+ return 0U;
+}
+
+} // namespace blimp
diff --git a/blimp/engine/browser/engine_render_widget_message_processor.h b/blimp/engine/browser/engine_render_widget_message_processor.h
new file mode 100644
index 0000000..3a60836
--- /dev/null
+++ b/blimp/engine/browser/engine_render_widget_message_processor.h
@@ -0,0 +1,91 @@
+// 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.
+
+#ifndef BLIMP_ENGINE_BROWSER_ENGINE_RENDER_WIDGET_MESSAGE_PROCESSOR_H_
+#define BLIMP_ENGINE_BROWSER_ENGINE_RENDER_WIDGET_MESSAGE_PROCESSOR_H_
+
+#include <vector>
+
+#include "base/containers/small_map.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "blimp/net/blimp_message_processor.h"
+#include "blimp/net/input_message_processor.h"
+
+namespace blink {
+class WebInputEvent;
+}
+
+namespace blimp {
+
+// Handles all incoming and outgoing protobuf message types tied to a specific
+// RenderWidget. This includes BlimpMessage::INPUT, BlimpMessage::COMPOSITOR,
+// and BlimpMessage::RENDER_WIDGET messages. Delegates can be added to be
+// notified of incoming messages. This class automatically handles dropping
+// stale BlimpMessage::RENDER_WIDGET messages from the client after a
+// RenderWidgetMessage::INITIALIZE message is sent.
+class EngineRenderWidgetMessageProcessor : public BlimpMessageProcessor {
+ public:
+ // A delegate to be notified of specific RenderWidget related incoming events.
+ class RenderWidgetMessageDelegate {
+ public:
+ // Called when the client is sending a WebInputEvent to the engine.
+ virtual void OnWebInputEvent(scoped_ptr<blink::WebInputEvent> event) = 0;
+
+ // Called when the client sent a CompositorMessage. These messages should
+ // be sent to the engine's render process so they can be processed by the
+ // RemoteChannel of the compositor.
+ virtual void OnCompositorMessageReceived(
+ const std::vector<uint8_t>& message) = 0;
+ };
+
+ EngineRenderWidgetMessageProcessor(
+ BlimpMessageProcessor* render_widget_message_processor,
+ BlimpMessageProcessor* compositor_message_processor);
+ ~EngineRenderWidgetMessageProcessor() override;
+
+ // Notifies the client that the RenderWidget for a particular WebContents has
+ // changed. When this is sent all incoming messages from the client sent
+ // before this message has been received will be dropped by this class.
+ void OnRenderWidgetInitialized(const int tab_id);
+
+ // Sends a CompositorMessage for |tab_id| to the client.
+ void SendCompositorMessage(const int tab_id,
+ const std::vector<uint8_t>& message);
+
+ // Sets a RenderWidgetMessageDelegate to be notified of all incoming
+ // RenderWidget related messages for |tab_id| from the client. There can only
+ // be one RenderWidgetMessageDelegate per tab.
+ void SetDelegate(const int tab_id, RenderWidgetMessageDelegate* delegate);
+ void RemoveDelegate(const int tab_id);
+
+ // BlimpMessageProcessor implementation.
+ void ProcessMessage(scoped_ptr<BlimpMessage> message,
+ const net::CompletionCallback& callback) override;
+
+ private:
+ // Returns nullptr if no delegate is found.
+ RenderWidgetMessageDelegate* FindDelegate(const int tab_id);
+
+ // Returns 0 if no id is found.
+ uint32_t GetRenderWidgetId(const int tab_id);
+
+ typedef base::SmallMap<std::map<int, RenderWidgetMessageDelegate*> >
+ DelegateMap;
+ typedef base::SmallMap<std::map<int, uint32_t> > RenderWidgetIdMap;
+
+ DelegateMap delegates_;
+ RenderWidgetIdMap render_widget_ids_;
+
+ InputMessageProcessor input_message_processor_;
+
+ BlimpMessageProcessor* render_widget_message_processor_;
+ BlimpMessageProcessor* compositor_message_processor_;
+
+ DISALLOW_COPY_AND_ASSIGN(EngineRenderWidgetMessageProcessor);
+};
+
+} // namespace blimp
+
+#endif // BLIMP_ENGINE_BROWSER_ENGINE_RENDER_WIDGET_MESSAGE_PROCESSOR_H_
diff --git a/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc b/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc
new file mode 100644
index 0000000..fd56f4c
--- /dev/null
+++ b/blimp/engine/browser/engine_render_widget_message_processor_unittest.cc
@@ -0,0 +1,208 @@
+// 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 "blimp/engine/browser/engine_render_widget_message_processor.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/numerics/safe_conversions.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/proto/compositor.pb.h"
+#include "blimp/common/proto/render_widget.pb.h"
+#include "blimp/net/input_message_generator.h"
+#include "net/base/net_errors.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+using testing::_;
+using testing::InvokeArgument;
+using testing::Ref;
+using testing::Return;
+using testing::SaveArg;
+
+namespace blimp {
+
+namespace {
+class MockBlimpMessageProcessor : public BlimpMessageProcessor {
+ public:
+ MockBlimpMessageProcessor() {}
+
+ ~MockBlimpMessageProcessor() override {}
+
+ // Adapts calls from ProcessMessage to MockableProcessMessage by
+ // unboxing the |message| scoped_ptr for GMock compatibility.
+ void ProcessMessage(scoped_ptr<BlimpMessage> message,
+ const net::CompletionCallback& callback) {
+ MockableProcessMessage(*message);
+ if (!callback.is_null())
+ callback.Run(net::OK);
+ }
+
+ MOCK_METHOD1(MockableProcessMessage,
+ void(const BlimpMessage& message));
+};
+
+class MockHostRenderWidgetMessageDelegate
+ : public EngineRenderWidgetMessageProcessor::RenderWidgetMessageDelegate {
+ public:
+ // EngineRenderWidgetMessageProcessor implementation.
+ void OnWebInputEvent(scoped_ptr<blink::WebInputEvent> event) override {
+ MockableOnWebInputEvent();
+ }
+
+ void OnCompositorMessageReceived(
+ const std::vector<uint8_t>& message) override {
+ MockableOnCompositorMessageReceived(message);
+ }
+
+ MOCK_METHOD0(MockableOnWebInputEvent, void());
+ MOCK_METHOD1(MockableOnCompositorMessageReceived,
+ void(const std::vector<uint8_t>& message));
+};
+
+MATCHER_P(CompMsgEquals, contents, "") {
+ if (contents.size() != arg.size())
+ return false;
+
+ return memcmp(contents.data(), arg.data(), contents.size()) == 0;
+}
+
+MATCHER_P3(BlimpCompMsgEquals, tab_id, rw_id, contents, "") {
+ if (contents.size() != arg.compositor().payload().size())
+ return false;
+
+ if (memcmp(contents.data(),
+ arg.compositor().payload().data(),
+ contents.size()) != 0) {
+ return false;
+ }
+
+ return arg.compositor().render_widget_id() == rw_id &&
+ arg.target_tab_id() == tab_id;
+}
+
+MATCHER_P2(BlimpRWMsgEquals, tab_id, rw_id, "") {
+ return arg.render_widget().render_widget_id() == rw_id &&
+ arg.target_tab_id() == tab_id;
+}
+
+void SendInputMessage(BlimpMessageProcessor* processor,
+ int tab_id,
+ uint32_t rw_id) {
+ blink::WebGestureEvent input_event;
+ input_event.type = blink::WebInputEvent::Type::GestureTap;
+
+ InputMessageGenerator generator;
+ scoped_ptr<BlimpMessage> message = generator.GenerateMessage(input_event);
+ message->set_type(BlimpMessage::INPUT);
+ message->set_target_tab_id(tab_id);
+ message->mutable_input()->set_render_widget_id(rw_id);
+
+ processor->ProcessMessage(message.Pass(),
+ net::CompletionCallback());
+}
+
+void SendCompositorMessage(BlimpMessageProcessor* processor,
+ int tab_id,
+ uint32_t rw_id,
+ const std::vector<uint8_t>& payload) {
+ scoped_ptr<BlimpMessage> message(new BlimpMessage);
+ message->set_type(BlimpMessage::COMPOSITOR);
+ message->set_target_tab_id(tab_id);
+
+ CompositorMessage* details = message->mutable_compositor();
+ details->set_render_widget_id(rw_id);
+ details->set_payload(payload.data(), base::checked_cast<int>(payload.size()));
+ processor->ProcessMessage(message.Pass(),
+ net::CompletionCallback());
+}
+
+} // namespace
+
+class EngineRenderWidgetMessageProcessorTest : public testing::Test {
+ public:
+ EngineRenderWidgetMessageProcessorTest()
+ : processor_(&out_processor_, &out_processor_) {}
+
+ void SetUp() override {
+ processor_.SetDelegate(1, &delegate1_);
+ processor_.SetDelegate(2, &delegate2_);
+
+ processor_.OnRenderWidgetInitialized(1);
+ processor_.OnRenderWidgetInitialized(2);
+ }
+
+ protected:
+ MockBlimpMessageProcessor out_processor_;
+ MockHostRenderWidgetMessageDelegate delegate1_;
+ MockHostRenderWidgetMessageDelegate delegate2_;
+ EngineRenderWidgetMessageProcessor processor_;
+};
+
+TEST_F(EngineRenderWidgetMessageProcessorTest, DelegateCallsOK) {
+ std::vector<uint8_t> payload = { 'd', 'a', 'v', 'i', 'd' };
+
+ EXPECT_CALL(delegate1_, MockableOnCompositorMessageReceived(
+ CompMsgEquals(payload))).Times(1);
+ SendCompositorMessage(&processor_, 1, 1U, payload);
+
+ EXPECT_CALL(delegate1_, MockableOnWebInputEvent()).Times(1);
+ SendInputMessage(&processor_, 1, 1U);
+
+ EXPECT_CALL(delegate2_, MockableOnCompositorMessageReceived(
+ CompMsgEquals(payload))).Times(1);
+ SendCompositorMessage(&processor_, 2, 1U, payload);
+
+ EXPECT_CALL(delegate2_, MockableOnWebInputEvent()).Times(1);
+ SendInputMessage(&processor_, 2, 1U);
+}
+
+TEST_F(EngineRenderWidgetMessageProcessorTest, DropsStaleMessages) {
+ std::vector<uint8_t> payload = { 'f', 'u', 'n' };
+
+ EXPECT_CALL(delegate1_, MockableOnCompositorMessageReceived(
+ CompMsgEquals(payload))).Times(1);
+ SendCompositorMessage(&processor_, 1, 1U, payload);
+
+ EXPECT_CALL(out_processor_,
+ MockableProcessMessage(BlimpRWMsgEquals(1, 2U))).Times(1);
+ processor_.OnRenderWidgetInitialized(1);
+
+ EXPECT_CALL(delegate1_, MockableOnCompositorMessageReceived(
+ CompMsgEquals(payload))).Times(0);
+ payload[0] = 'a';
+ SendCompositorMessage(&processor_, 1, 1U, payload);
+
+ EXPECT_CALL(delegate1_, MockableOnWebInputEvent()).Times(0);
+ SendInputMessage(&processor_, 1, 1U);
+
+ EXPECT_CALL(delegate1_, MockableOnCompositorMessageReceived(
+ CompMsgEquals(payload))).Times(1);
+ SendCompositorMessage(&processor_, 1, 2U, payload);
+
+ EXPECT_CALL(delegate1_, MockableOnWebInputEvent()).Times(1);
+ SendInputMessage(&processor_, 1, 2U);
+}
+
+TEST_F(EngineRenderWidgetMessageProcessorTest,
+ RepliesHaveCorrectRenderWidgetId) {
+ std::vector<uint8_t> payload = { 'a', 'b', 'c', 'd' };
+
+ EXPECT_CALL(out_processor_,
+ MockableProcessMessage(BlimpRWMsgEquals(1, 2U))).Times(1);
+ processor_.OnRenderWidgetInitialized(1);
+
+ EXPECT_CALL(out_processor_,
+ MockableProcessMessage(BlimpRWMsgEquals(2, 2U))).Times(1);
+ processor_.OnRenderWidgetInitialized(2);
+
+ EXPECT_CALL(out_processor_, MockableProcessMessage(
+ BlimpCompMsgEquals(1, 2U, payload))).Times(1);
+
+ processor_.SendCompositorMessage(1, payload);
+}
+
+
+} // namespace blimp