diff options
author | dtrainor <dtrainor@chromium.org> | 2015-11-30 16:53:05 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-01 00:54:00 +0000 |
commit | 160f8eca573286f3bb369975ac2e9de63b0cc477 (patch) | |
tree | 3a416ada921c22f0f3902badd415af17ba73a73c /blimp/engine | |
parent | 7f3d85b096f66870a15b37c2f40b219b2e292693 (diff) | |
download | chromium_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.gn | 8 | ||||
-rw-r--r-- | blimp/engine/DEPS | 1 | ||||
-rw-r--r-- | blimp/engine/browser/BUILD.gn | 22 | ||||
-rw-r--r-- | blimp/engine/browser/blimp_engine_session.cc | 72 | ||||
-rw-r--r-- | blimp/engine/browser/blimp_engine_session.h | 30 | ||||
-rw-r--r-- | blimp/engine/browser/engine_render_widget_message_processor.cc | 136 | ||||
-rw-r--r-- | blimp/engine/browser/engine_render_widget_message_processor.h | 91 | ||||
-rw-r--r-- | blimp/engine/browser/engine_render_widget_message_processor_unittest.cc | 208 |
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 |