summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-16 13:34:08 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-16 13:34:08 +0000
commitc708db4675caea8773ccf88a5762d33035073e2d (patch)
tree643c56b05e66b960af36fc8964be555dc6a3554c
parent0520e8a4859a2bb806638c00aa03daf5612d50dc (diff)
downloadchromium_src-c708db4675caea8773ccf88a5762d33035073e2d.zip
chromium_src-c708db4675caea8773ccf88a5762d33035073e2d.tar.gz
chromium_src-c708db4675caea8773ccf88a5762d33035073e2d.tar.bz2
Reapply r51857 to start building chromoting plugin. Update for ppapi changes.
This should work now after the ppapi roll to r164 that fixes the -fvisibility=hidden being removed in the linux shlib build. Original Review here: http://codereview.chromium.org/2858037 BUG=none TEST=try bots + local run of PPAPITest with a shared_library build. Review URL: http://codereview.chromium.org/3038001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52658 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--remoting/client/chromoting_client.cc10
-rw-r--r--remoting/client/chromoting_client.h4
-rw-r--r--remoting/client/plugin/chromoting_plugin.cc82
-rw-r--r--remoting/client/plugin/chromoting_plugin.h38
-rw-r--r--remoting/client/plugin/pepper_entrypoints.cc235
-rw-r--r--remoting/client/plugin/pepper_util.cc31
-rw-r--r--remoting/client/plugin/pepper_util.h32
-rw-r--r--remoting/client/plugin/pepper_view.cc234
-rw-r--r--remoting/client/plugin/pepper_view.h51
-rw-r--r--remoting/remoting.gyp5
10 files changed, 332 insertions, 390 deletions
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc
index cad1993..39f18b4 100644
--- a/remoting/client/chromoting_client.cc
+++ b/remoting/client/chromoting_client.cc
@@ -8,9 +8,9 @@
#include "remoting/client/chromoting_view.h"
#include "remoting/client/host_connection.h"
-static const uint32 kCreatedColor = 0xff0000ff;
-static const uint32 kDisconnectedColor = 0xff00ff00;
-static const uint32 kFailedColor = 0xffff0000;
+static const uint32 kCreatedColor = 0xffccccff;
+static const uint32 kDisconnectedColor = 0xff00ccff;
+static const uint32 kFailedColor = 0xffcc00ff;
namespace remoting {
@@ -162,9 +162,9 @@ void ChromotingClient::DoHandleUpdate(HostMessage* msg) {
void ChromotingClient::DoEndUpdate(HostMessage* msg) {
DCHECK_EQ(message_loop(), MessageLoop::current());
- DCHECK(msg->has_update_stream_packet());
+ DCHECK(msg->has_end_update_stream());
- view_->HandleUpdateStreamPacket(msg);
+ view_->HandleEndUpdateStream(msg);
}
} // namespace remoting
diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h
index 587f1fb..50cc0dc 100644
--- a/remoting/client/chromoting_client.h
+++ b/remoting/client/chromoting_client.h
@@ -28,6 +28,10 @@ class ChromotingClient : public HostConnection::HostEventCallback {
// Sets the viewport to do display. The viewport may be larger and/or
// smaller than the actual image background being displayed.
+ //
+ // TODO(ajwong): This doesn't make sense to have here. We're going to have
+ // threading isseus since pepper view needs to be called from the main pepper
+ // thread synchronously really.
virtual void SetViewport(int x, int y, int width, int height);
// HostConnection::HostEventCallback implementation.
diff --git a/remoting/client/plugin/chromoting_plugin.cc b/remoting/client/plugin/chromoting_plugin.cc
index a312426..160bf3a 100644
--- a/remoting/client/plugin/chromoting_plugin.cc
+++ b/remoting/client/plugin/chromoting_plugin.cc
@@ -7,6 +7,7 @@
#include <string>
#include <vector>
+#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "remoting/client/chromoting_client.h"
@@ -17,7 +18,6 @@
#include "third_party/ppapi/c/pp_event.h"
#include "third_party/ppapi/c/pp_rect.h"
#include "third_party/ppapi/cpp/completion_callback.h"
-#include "third_party/ppapi/cpp/image_data.h"
using std::string;
using std::vector;
@@ -26,13 +26,9 @@ namespace remoting {
const char* ChromotingPlugin::kMimeType = "pepper-application/x-chromoting";
-ChromotingPlugin::ChromotingPlugin(PP_Instance pp_instance,
- const PPB_Instance* ppb_instance_funcs)
- : width_(0),
- height_(0),
- drawing_context_(NULL),
- pp_instance_(pp_instance),
- ppb_instance_funcs_(ppb_instance_funcs) {
+ChromotingPlugin::ChromotingPlugin(PP_Instance pp_instance)
+ : pp::Instance(pp_instance),
+ pepper_main_loop_dont_post_to_me_(NULL) {
}
ChromotingPlugin::~ChromotingPlugin() {
@@ -53,6 +49,19 @@ ChromotingPlugin::~ChromotingPlugin() {
bool ChromotingPlugin::Init(uint32_t argc,
const char* argn[],
const char* argv[]) {
+ CHECK(pepper_main_loop_dont_post_to_me_ == NULL);
+
+ // Record the current thread. This function should only be invoked by the
+ // plugin thread, so we capture the current message loop and assume it is
+ // indeed the plugin thread.
+ //
+ // We're abusing the pepper API slightly here. We know we're running as an
+ // internal plugin, and thus we are on the pepper main thread that uses a
+ // message loop.
+ //
+ // TODO(ajwong): See if there is a method for querying what thread we're on
+ // from inside the pepper API.
+ pepper_main_loop_dont_post_to_me_ = MessageLoop::current();
LOG(INFO) << "Started ChromotingPlugin::Init";
// Extract the URL from the arguments.
@@ -87,21 +96,23 @@ bool ChromotingPlugin::Init(uint32_t argc,
// Create the chromting objects.
host_connection_.reset(new JingleHostConnection(network_thread_.get()));
- /*
- view_.reset(new PepperView(main_thread_->message_loop(), device_,
- instance()));
- */
- //client_.reset(new ChromotingClient(main_thread_->message_loop(),
- // host_connection_.get(), view_.get()));
+ view_.reset(new PepperView(this));
+ client_.reset(new ChromotingClient(main_thread_->message_loop(),
+ host_connection_.get(), view_.get()));
+
+ // Default to a medium grey.
+ view_->SetSolidFill(0xFFCDCDCD);
// Kick off the connection.
- //host_connection_->Connect(user_id, auth_token, host_jid, client_.get());
+ host_connection_->Connect(user_id, auth_token, host_jid, client_.get());
return true;
}
void ChromotingPlugin::ViewChanged(const PP_Rect& position,
const PP_Rect& clip) {
+ DCHECK(CurrentlyOnPluginThread());
+
// TODO(ajwong): This is going to be a race condition when the view changes
// and we're in the middle of a Paint().
LOG(INFO) << "ViewChanged "
@@ -110,43 +121,18 @@ void ChromotingPlugin::ViewChanged(const PP_Rect& position,
<< position.size.width << ","
<< position.size.height;
- // TODO(ajwong): Do we care about the position? Probably not...
- if (position.size.width == width_ || position.size.height == height_)
- return;
-
- width_ = position.size.width;
- height_ = position.size.height;
-
- /*
- * TODO(ajwong): Reenable this code once we fingure out how we want to
- * abstract away the C-api for DeviceContext2D.
- device_context_ = pp::DeviceContext2D(width_, height_, false);
- if (!ppb_instance_funcs_->BindGraphicsDeviceContext(
- pp_instance_,
- device_context_.pp_resource())) {
- LOG(ERROR) << "Couldn't bind the device context.";
- return;
- }
-
- pp::ImageData image(PP_IMAGEDATAFORMAT_BGRA_PREMUL, width_, height_, false);
- if (!image.is_null()) {
- for (int y = 0; y < image.height(); y++) {
- for (int x = 0; x < image.width(); x++) {
- *image.GetAddr32(x, y) = 0xccff00cc;
- }
- }
- device_context_.ReplaceContents(&image);
- device_context_.Flush(pp::CompletionCallback(NULL, this));
- } else {
- LOG(ERROR) << "Unable to allocate image.";
- }
- */
+ view_->SetViewport(position.point.x, position.point.y,
+ position.size.width, position.size.height);
+ view_->Paint();
+}
- //client_->SetViewport(0, 0, width_, height_);
- //client_->Repaint();
+bool ChromotingPlugin::CurrentlyOnPluginThread() const {
+ return pepper_main_loop_dont_post_to_me_ == MessageLoop::current();
}
bool ChromotingPlugin::HandleEvent(const PP_Event& event) {
+ DCHECK(CurrentlyOnPluginThread());
+
switch (event.type) {
case PP_EVENT_TYPE_MOUSEDOWN:
case PP_EVENT_TYPE_MOUSEUP:
diff --git a/remoting/client/plugin/chromoting_plugin.h b/remoting/client/plugin/chromoting_plugin.h
index 757e038..0aac051 100644
--- a/remoting/client/plugin/chromoting_plugin.h
+++ b/remoting/client/plugin/chromoting_plugin.h
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// TODO(ajwong): We need to come up with a better description of the
+// responsibilities for each thread.
+
#ifndef REMOTING_CLIENT_PLUGIN_CHROMOTING_PLUGIN_H_
#define REMOTING_CLIENT_PLUGIN_CHROMOTING_PLUGIN_H_
@@ -15,12 +18,19 @@
#include "third_party/ppapi/c/pp_instance.h"
#include "third_party/ppapi/c/pp_rect.h"
#include "third_party/ppapi/c/pp_resource.h"
-#include "third_party/ppapi/c/ppb_instance.h"
+#include "third_party/ppapi/cpp/instance.h"
+#include "third_party/ppapi/cpp/device_context_2d.h"
+
+class MessageLoop;
namespace base {
class Thread;
} // namespace base
+namespace pp {
+class Module;
+} // namespace pp
+
namespace remoting {
class ChromotingClient;
@@ -28,23 +38,20 @@ class HostConnection;
class JingleThread;
class PepperView;
-class ChromotingClient;
-
-class ChromotingPlugin {
+class ChromotingPlugin : public pp::Instance {
public:
// The mimetype for which this plugin is registered.
- //
- // TODO(ajwong): Mimetype doesn't really make sense for us as the trigger
- // point. I think we should handle a special protocol (eg., chromotocol://)
static const char *kMimeType;
- ChromotingPlugin(PP_Instance instance, const PPB_Instance* instance_funcs);
+ ChromotingPlugin(PP_Instance instance);
virtual ~ChromotingPlugin();
virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]);
virtual bool HandleEvent(const PP_Event& event);
virtual void ViewChanged(const PP_Rect& position, const PP_Rect& clip);
+ virtual bool CurrentlyOnPluginThread() const;
+
private:
FRIEND_TEST(ChromotingPluginTest, ParseUrl);
FRIEND_TEST(ChromotingPluginTest, TestCaseSetup);
@@ -54,14 +61,13 @@ class ChromotingPlugin {
std::string* auth_token,
std::string* host_jid);
- // Size of the plugin window.
- int width_;
- int height_;
-
- PP_Resource drawing_context_;
-
- PP_Instance pp_instance_;
- const PPB_Instance* ppb_instance_funcs_;
+ // Since we're an internal plugin, we can just grab the message loop during
+ // init to figure out which thread we're on. This should only be used to
+ // sanity check which thread we're executing on. Do not post task here!
+ // Instead, use PPB_Core:CallOnMainThread() in the pepper api.
+ //
+ // TODO(ajwong): Think if there is a better way to safeguard this.
+ MessageLoop* pepper_main_loop_dont_post_to_me_;
scoped_ptr<base::Thread> main_thread_;
scoped_ptr<JingleThread> network_thread_;
diff --git a/remoting/client/plugin/pepper_entrypoints.cc b/remoting/client/plugin/pepper_entrypoints.cc
index ad21956..1613c1d 100644
--- a/remoting/client/plugin/pepper_entrypoints.cc
+++ b/remoting/client/plugin/pepper_entrypoints.cc
@@ -4,236 +4,59 @@
#include "remoting/client/plugin/pepper_entrypoints.h"
+#include "base/message_loop.h"
#include "remoting/client/plugin/chromoting_plugin.h"
+#include "third_party/ppapi/c/pp_errors.h"
#include "third_party/ppapi/c/pp_instance.h"
#include "third_party/ppapi/c/pp_module.h"
-#include "third_party/ppapi/c/ppp_instance.h"
+#include "third_party/ppapi/c/ppb_instance.h"
#include "third_party/ppapi/cpp/instance.h"
#include "third_party/ppapi/cpp/module.h"
-static const int kModuleInitSuccess = 0;
-static const int kModuleInitFailure = 1;
+static pp::Module* g_module_singleton = NULL;
-namespace remoting {
-
-// Fork of ppapi::Module
-//
-// TODO(ajwong): Generalize this into something that other internal plugins can
-// use. Either that, or attempt to refactor the external ppapi C++ wrapper to
-// make it friendly for multiple Modules in one process. I think we can do this
-// by:
-// 1) Moving the singleton Module instance + C-bindings into another class
-// (eg., ModuleExporter) under a different gyp targe.
-// 2) Extracting the idea of a "Browser" out of the module that returns
-// PPB_Core, etc. This can be a singleton per process regardless of
-// module.
-// 3) Migrate all PPB related objects to get data out of Browser interface
-// instead of Module::Get().
-class ChromotingModule {
- public:
- ChromotingModule() {}
-
- // This function will be automatically called after the object is created.
- // This is where you can put functions that rely on other parts of the API,
- // now that the module has been created.
- virtual bool Init() { return true; }
-
- PP_Module pp_module() const { return pp_module_; }
- const PPB_Core& core() const { return *core_; }
-
- // Implements GetInterface for the browser to get plugin interfaces. Override
- // if you need to implement your own interface types that this wrapper
- // doesn't support.
- virtual const void* GetInstanceInterface(const char* interface_name) {
- if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)
- return &instance_interface_;
-
- return NULL;
- }
-
- // Returns an interface in the browser.
- const void* GetBrowserInterface(const char* interface_name) {
- return get_browser_interface_(interface_name);
- }
-
- // Returns the object associated with this PP_Instance, or NULL if one is
- // not found.
- ChromotingPlugin* InstanceForPPInstance(PP_Instance instance) {
- InstanceMap::iterator found = current_instances_.find(instance);
- if (found == current_instances_.end())
- return NULL;
- return found->second;
- }
+namespace pp {
- // Sets the browser interface and calls the regular init function that
- // can be overridden by the base classes.
- //
- // TODO(brettw) make this private when I can figure out how to make the
- // initialize function a friend.
- bool InternalInit(PP_Module mod,
- PPB_GetInterface get_browser_interface) {
- pp_module_ = mod;
- get_browser_interface_ = get_browser_interface;
- core_ = reinterpret_cast<const PPB_Core*>(GetBrowserInterface(
- PPB_CORE_INTERFACE));
- if (!core_)
- return false; // Can't run without the core interface.
-
- return Init();
- }
-
- // Implementation of Global PPP functions ---------------------------------
- static int PPP_InitializeModule(PP_Module module_id,
- PPB_GetInterface get_browser_interface) {
- ChromotingModule* module = new ChromotingModule();
- if (!module)
- return kModuleInitFailure;
-
- if (!module->InternalInit(module_id, get_browser_interface)) {
- delete module;
- return kModuleInitFailure;
- }
-
- module_singleton_ = module;
- return kModuleInitSuccess;
- }
+Module* Module::Get() {
+ return g_module_singleton;
+}
- static void PPP_ShutdownModule() {
- delete module_singleton_;
- module_singleton_ = NULL;
- }
+} // namespace pp
- static const void* PPP_GetInterface(const char* interface_name) {
- if (!module_singleton_)
- return NULL;
- return module_singleton_->GetInstanceInterface(interface_name);
- }
+namespace remoting {
+class ChromotingModule : public pp::Module {
protected:
virtual ChromotingPlugin* CreateInstance(PP_Instance instance) {
- const PPB_Instance* ppb_instance_funcs =
- reinterpret_cast<const PPB_Instance *>(
- module_singleton_->GetBrowserInterface(PPB_INSTANCE_INTERFACE));
- return new ChromotingPlugin(instance, ppb_instance_funcs);
- }
-
- private:
- static bool Instance_New(PP_Instance instance) {
- if (!module_singleton_)
- return false;
- ChromotingPlugin* obj = module_singleton_->CreateInstance(instance);
- if (obj) {
- module_singleton_->current_instances_[instance] = obj;
- return true;
- }
- return false;
- }
-
- static void Instance_Delete(PP_Instance instance) {
- if (!module_singleton_)
- return;
- ChromotingModule::InstanceMap::iterator found =
- module_singleton_->current_instances_.find(instance);
- if (found == module_singleton_->current_instances_.end())
- return;
-
- // Remove it from the map before deleting to try to catch reentrancy.
- ChromotingPlugin* obj = found->second;
- module_singleton_->current_instances_.erase(found);
- delete obj;
- }
-
- static bool Instance_Initialize(PP_Instance pp_instance,
- uint32_t argc,
- const char* argn[],
- const char* argv[]) {
- if (!module_singleton_)
- return false;
- ChromotingPlugin* instance =
- module_singleton_->InstanceForPPInstance(pp_instance);
- if (!instance)
- return false;
- return instance->Init(argc, argn, argv);
- }
-
- static bool Instance_HandleDocumentLoad(PP_Instance pp_instance,
- PP_Resource url_loader) {
- return false;
- }
-
- static bool Instance_HandleEvent(PP_Instance pp_instance,
- const PP_Event* event) {
- if (!module_singleton_)
- return false;
- ChromotingPlugin* instance =
- module_singleton_->InstanceForPPInstance(pp_instance);
- if (!instance)
- return false;
- return instance->HandleEvent(*event);
- }
-
- static PP_Var Instance_GetInstanceObject(PP_Instance pp_instance) {
- PP_Var var;
- var.type = PP_VARTYPE_VOID;
- return var;
+ return new ChromotingPlugin(instance);
}
-
- static void Instance_ViewChanged(PP_Instance pp_instance,
- const PP_Rect* position,
- const PP_Rect* clip) {
- if (!module_singleton_)
- return;
- ChromotingPlugin* instance =
- module_singleton_->InstanceForPPInstance(pp_instance);
- if (!instance)
- return;
- instance->ViewChanged(*position, *clip);
- }
-
- // Bindings and identifiers to and from the browser.
- PP_Module pp_module_;
- PPB_GetInterface get_browser_interface_;
- PPB_Core const* core_;
-
- // Instance tracking.
- typedef std::map<PP_Instance, ChromotingPlugin*> InstanceMap;
- InstanceMap current_instances_;
-
- // Static members for the ppapi C-bridge.
- static PPP_Instance instance_interface_;
- static ChromotingModule* module_singleton_;
-
- DISALLOW_COPY_AND_ASSIGN(ChromotingModule);
};
-ChromotingModule* ChromotingModule::module_singleton_ = NULL;
+// Implementation of Global PPP functions ---------------------------------
+int32_t PPP_InitializeModule(PP_Module module_id,
+ PPB_GetInterface get_browser_interface) {
+ ChromotingModule* module = new ChromotingModule();
+ if (!module)
+ return PP_ERROR_FAILED;
-PPP_Instance ChromotingModule::instance_interface_ = {
- &ChromotingModule::Instance_New,
- &ChromotingModule::Instance_Delete,
- &ChromotingModule::Instance_Initialize,
- &ChromotingModule::Instance_HandleDocumentLoad,
- &ChromotingModule::Instance_HandleEvent,
- &ChromotingModule::Instance_GetInstanceObject,
- &ChromotingModule::Instance_ViewChanged,
-};
+ if (!module->InternalInit(module_id, get_browser_interface)) {
+ delete module;
+ return PP_ERROR_FAILED;
+ }
-// Implementation of Global PPP functions ---------------------------------
-//
-// TODO(ajwong): This is to get around friending issues. Fix it after we decide
-// whether or not ChromotingModule should be generalized.
-int PPP_InitializeModule(PP_Module module_id,
- PPB_GetInterface get_browser_interface) {
- return ChromotingModule::PPP_InitializeModule(module_id,
- get_browser_interface);
+ g_module_singleton = module;
+ return PP_OK;
}
void PPP_ShutdownModule() {
- return ChromotingModule::PPP_ShutdownModule();
+ delete pp::Module::Get();
+ g_module_singleton = NULL;
}
const void* PPP_GetInterface(const char* interface_name) {
- return ChromotingModule::PPP_GetInterface(interface_name);
+ if (!pp::Module::Get())
+ return NULL;
+ return pp::Module::Get()->GetInstanceInterface(interface_name);
}
} // namespace remoting
diff --git a/remoting/client/plugin/pepper_util.cc b/remoting/client/plugin/pepper_util.cc
new file mode 100644
index 0000000..7c91233
--- /dev/null
+++ b/remoting/client/plugin/pepper_util.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 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 "remoting/client/plugin/pepper_util.h"
+
+#include "base/task.h"
+#include "third_party/ppapi/c/pp_completion_callback.h"
+#include "third_party/ppapi/cpp/module.h"
+
+namespace remoting {
+
+void CompletionCallbackTaskAdapter(void* user_data, int32_t not_used) {
+ Task* task = reinterpret_cast<Task*>(user_data);
+ task->Run();
+ delete task;
+}
+
+pp::CompletionCallback TaskToCompletionCallback(Task* task) {
+ return pp::CompletionCallback(&CompletionCallbackTaskAdapter, task);
+}
+
+void RunTaskOnPluginThread(Task* task) {
+ pp::Module::Get()->core()->CallOnMainThread(
+ 0 /* run immediately */,
+ TaskToCompletionCallback(task),
+ 0 /* unused value */
+ );
+}
+
+} // namespace remoting
diff --git a/remoting/client/plugin/pepper_util.h b/remoting/client/plugin/pepper_util.h
new file mode 100644
index 0000000..6c6cfb0
--- /dev/null
+++ b/remoting/client/plugin/pepper_util.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 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 REMOTING_CLIENT_PLUGIN_PLUGIN_UTIL_H_
+#define REMOTING_CLIENT_PLUGIN_PLUGIN_UTIL_H_
+
+#include "base/basictypes.h"
+
+#include "third_party/ppapi/cpp/completion_callback.h"
+
+class Task;
+
+namespace remoting {
+
+// Function for adapting a Chromium style Task into a
+// PP_CompletionCallback friendly function. The Task object should be passed
+// as |user_data|. This function will invoke Task::Run() on |user_data| when
+// called, and then delete |user_data|.
+void CompletionCallbackTaskAdapter(void* user_data, int32_t not_used);
+
+// Converts a Task* to a pp::CompletionCallback suitable for use with ppapi C++
+// APIs that require a pp::CompletionCallback. Takes ownership of |task|.
+pp::CompletionCallback TaskToCompletionCallback(Task* task);
+
+// Posts the current task to the plugin's main thread. Takes ownership of
+// |task|.
+void RunTaskOnPluginThread(Task* task);
+
+} // namespace remoting
+
+#endif // REMOTING_CLIENT_PLUGIN_PLUGIN_UTIL_H_
diff --git a/remoting/client/plugin/pepper_view.cc b/remoting/client/plugin/pepper_view.cc
index d66624b5..a6ebc13 100644
--- a/remoting/client/plugin/pepper_view.cc
+++ b/remoting/client/plugin/pepper_view.cc
@@ -6,14 +6,17 @@
#include "base/message_loop.h"
#include "remoting/client/decoder_verbatim.h"
+#include "remoting/client/plugin/chromoting_plugin.h"
+#include "remoting/client/plugin/pepper_util.h"
+#include "third_party/ppapi/cpp/device_context_2d.h"
+#include "third_party/ppapi/cpp/image_data.h"
+#include "third_party/ppapi/cpp/point.h"
+#include "third_party/ppapi/cpp/size.h"
namespace remoting {
-PepperView::PepperView(MessageLoop* message_loop, NPDevice* rendering_device,
- NPP plugin_instance)
- : message_loop_(message_loop),
- rendering_device_(rendering_device),
- plugin_instance_(plugin_instance),
+PepperView::PepperView(ChromotingPlugin* plugin)
+ : plugin_(plugin),
backing_store_width_(0),
backing_store_height_(0),
viewport_x_(0),
@@ -28,127 +31,174 @@ PepperView::~PepperView() {
}
void PepperView::Paint() {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &PepperView::DoPaint));
-}
-
-void PepperView::SetSolidFill(uint32 color) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &PepperView::DoSetSolidFill, color));
-}
-
-void PepperView::UnsetSolidFill() {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &PepperView::DoUnsetSolidFill));
-}
-
-void PepperView::SetViewport(int x, int y, int width, int height) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &PepperView::DoSetViewport,
- x, y, width, height));
-}
-
-void PepperView::SetBackingStoreSize(int width, int height) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &PepperView::DoSetBackingStoreSize,
- width, height));
-}
-
-void PepperView::HandleBeginUpdateStream(HostMessage* msg) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &PepperView::DoHandleBeginUpdateStream, msg));
-}
-
-void PepperView::HandleUpdateStreamPacket(HostMessage* msg) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &PepperView::DoHandleUpdateStreamPacket, msg));
-}
-
-void PepperView::HandleEndUpdateStream(HostMessage* msg) {
- message_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &PepperView::DoHandleEndUpdateStream, msg));
-}
-
-void PepperView::DoPaint() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
-
- LOG(INFO) << "Starting PepperView::DoPaint";
-
- NPDeviceContext2D context;
- NPDeviceContext2DConfig config;
- rendering_device_->initializeContext(plugin_instance_, &config, &context);
+ if (!plugin_->CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(NewRunnableMethod(this, &PepperView::Paint));
+ return;
+ }
- uint32* output_bitmap = static_cast<uint32*>(context.region);
+ // TODO(ajwong): We shouldn't assume the image data format.
+ pp::ImageData image(PP_IMAGEDATAFORMAT_BGRA_PREMUL,
+ pp::Size(viewport_width_, viewport_height_),
+ false);
+ if (image.is_null()) {
+ LOG(ERROR) << "Unable to allocate image.";
+ return;
+ }
- // TODO(ajwong): Remove debugging code and actually hook up real painting
- // logic from the decoder.
- LOG(INFO) << "Painting top: " << context.dirty.top
- << " bottom: " << context.dirty.bottom
- << " left: " << context.dirty.left
- << " right: " << context.dirty.right;
- for (int i = context.dirty.top; i < context.dirty.bottom; ++i) {
- for (int j = context.dirty.left; j < context.dirty.right; ++j) {
- *output_bitmap++ = static_fill_color_;
+ if (is_static_fill_) {
+ for (int y = 0; y < image.size().height(); y++) {
+ for (int x = 0; x < image.size().width(); x++) {
+ *image.GetAddr32(pp::Point(x, y)) = static_fill_color_;
+ }
+ }
+ } else if (frame_) {
+ uint32_t* frame_data =
+ reinterpret_cast<uint32_t*>(frame_->data(media::VideoFrame::kRGBPlane));
+ int max_height = std::min(backing_store_height_, image.size().height());
+ int max_width = std::min(backing_store_width_, image.size().width());
+ for (int y = 0; y < max_height; y++) {
+ for (int x = 0; x < max_width; x++) {
+ // Force alpha to be set to 255.
+ *image.GetAddr32(pp::Point(x, y)) =
+ frame_data[y*backing_store_width_ + x] | 0xFF000000;
+ }
}
+ } else {
+ // Nothing to paint. escape!
+ //
+ // TODO(ajwong): This is an ugly control flow. fix.
+ return;
}
-
- rendering_device_->flushContext(plugin_instance_, &context, NULL, NULL);
- LOG(INFO) << "Finishing PepperView::DoPaint";
+ device_context_.ReplaceContents(&image);
+ device_context_.Flush(TaskToCompletionCallback(
+ NewRunnableMethod(this, &PepperView::OnPaintDone)));
}
-void PepperView::DoSetSolidFill(uint32 color) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+void PepperView::SetSolidFill(uint32 color) {
+ if (!plugin_->CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(
+ NewRunnableMethod(this, &PepperView::SetSolidFill, color));
+ return;
+ }
is_static_fill_ = true;
static_fill_color_ = color;
}
-void PepperView::DoUnsetSolidFill() {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+void PepperView::UnsetSolidFill() {
+ if (!plugin_->CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(
+ NewRunnableMethod(this, &PepperView::UnsetSolidFill));
+ return;
+ }
is_static_fill_ = false;
}
-void PepperView::DoSetViewport(int x, int y, int width, int height) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+void PepperView::SetViewport(int x, int y, int width, int height) {
+ if (!plugin_->CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(NewRunnableMethod(this, &PepperView::SetViewport,
+ x, y, width, height));
+ return;
+ }
+ // TODO(ajwong): Should we ignore x & y updates? What do those even mean?
+
+ // TODO(ajwong): What does viewport x, y mean to a plugin anyways?
viewport_x_ = x;
viewport_y_ = y;
viewport_width_ = width;
viewport_height_ = height;
+
+ device_context_ =
+ pp::DeviceContext2D(pp::Size(viewport_width_, viewport_height_), false);
+ if (!plugin_->BindGraphicsDeviceContext(device_context_)) {
+ LOG(ERROR) << "Couldn't bind the device context.";
+ return;
+ }
}
-void PepperView::DoSetBackingStoreSize(int width, int height) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+void PepperView::SetBackingStoreSize(int width, int height) {
+ if (!plugin_->CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(NewRunnableMethod(this,
+ &PepperView::SetBackingStoreSize,
+ width, height));
+ return;
+ }
backing_store_width_ = width;
backing_store_height_ = height;
}
-void PepperView::DoHandleBeginUpdateStream(HostMessage* msg) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+void PepperView::HandleBeginUpdateStream(HostMessage* msg) {
+ if (!plugin_->CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(
+ NewRunnableMethod(this, &PepperView::HandleBeginUpdateStream,
+ msg));
+ return;
+ }
+
+ scoped_ptr<HostMessage> deleter(msg);
- NOTIMPLEMENTED();
+ // TODO(hclam): Use the information from the message to create the decoder.
+ // We lazily construct the decoder.
+ if (!decoder_.get()) {
+ decoder_.reset(new DecoderVerbatim());
+ }
+
+ if (!frame_) {
+ media::VideoFrame::CreateFrame(media::VideoFrame::RGB32,
+ backing_store_width_,
+ backing_store_height_,
+ base::TimeDelta(), base::TimeDelta(),
+ &frame_);
+ }
+
+ // Tell the decoder to do start decoding.
+ decoder_->BeginDecode(frame_, &update_rects_,
+ NewRunnableMethod(this, &PepperView::OnPartialDecodeDone),
+ NewRunnableMethod(this, &PepperView::OnDecodeDone));
+}
+
+void PepperView::HandleUpdateStreamPacket(HostMessage* msg) {
+ if (!plugin_->CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(
+ NewRunnableMethod(this, &PepperView::HandleUpdateStreamPacket,
+ msg));
+ return;
+ }
+
+ decoder_->PartialDecode(msg);
}
-void PepperView::DoHandleUpdateStreamPacket(HostMessage* msg) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
+void PepperView::HandleEndUpdateStream(HostMessage* msg) {
+ if (!plugin_->CurrentlyOnPluginThread()) {
+ RunTaskOnPluginThread(
+ NewRunnableMethod(this, &PepperView::HandleEndUpdateStream,
+ msg));
+ return;
+ }
+
+ scoped_ptr<HostMessage> deleter(msg);
+ decoder_->EndDecode();
+}
+
+void PepperView::OnPaintDone() {
+ // TODO(ajwong):Probably should set some variable to allow repaints to
+ // actually paint.
+ return;
+}
- NOTIMPLEMENTED();
+void PepperView::OnPartialDecodeDone() {
+ all_update_rects_.insert(all_update_rects_.begin() +
+ all_update_rects_.size(),
+ update_rects_.begin(), update_rects_.end());
+ Paint();
+ // TODO(ajwong): Need to block here to be synchronous.
}
-void PepperView::DoHandleEndUpdateStream(HostMessage* msg) {
- DCHECK_EQ(message_loop_, MessageLoop::current());
- NOTIMPLEMENTED();
+void PepperView::OnDecodeDone() {
}
} // namespace remoting
diff --git a/remoting/client/plugin/pepper_view.h b/remoting/client/plugin/pepper_view.h
index 9dc8a56..655b9ae 100644
--- a/remoting/client/plugin/pepper_view.h
+++ b/remoting/client/plugin/pepper_view.h
@@ -2,30 +2,38 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This class is an implementation of the ChromotingView using Pepper devices
+// as the backing stores. The public APIs to this class are thread-safe.
+// Calls will dispatch any interaction with the pepper API onto the pepper
+// main thread.
+//
+// TODO(ajwong): We need to better understand the threading semantics of this
+// class. Currently, we're just going to always run everything on the pepper
+// main thread. Is this smart?
+
#ifndef REMOTING_CLIENT_PLUGIN_PEPPER_VIEW_H_
#define REMOTING_CLIENT_PLUGIN_PEPPER_VIEW_H_
#include "base/scoped_ptr.h"
#include "base/task.h"
+#include "media/base/video_frame.h"
#include "remoting/client/chromoting_view.h"
-#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/npapi_extensions.h"
-
-class MessageLoop;
+#include "remoting/client/decoder.h"
+#include "third_party/ppapi/cpp/device_context_2d.h"
namespace remoting {
+class ChromotingPlugin;
class Decoder;
class PepperView : public ChromotingView {
public:
- // Constructs a PepperView that draw to the |rendering_device|. The
+ // Constructs a PepperView that draws to the |rendering_device|. The
// |rendering_device| instance must outlive this class.
//
// TODO(ajwong): This probably needs to synchronize with the pepper thread
// to be safe.
- PepperView(MessageLoop* message_loop, NPDevice* rendering_device,
- NPP plugin_instance);
+ explicit PepperView(ChromotingPlugin* plugin);
virtual ~PepperView();
// ChromotingView implementation.
@@ -39,21 +47,16 @@ class PepperView : public ChromotingView {
virtual void HandleEndUpdateStream(HostMessage* msg);
private:
- void DoPaint();
- void DoSetSolidFill(uint32 color);
- void DoUnsetSolidFill();
- void DoSetViewport(int x, int y, int width, int height);
- void DoSetBackingStoreSize(int width, int height);
- void DoHandleBeginUpdateStream(HostMessage* msg);
- void DoHandleUpdateStreamPacket(HostMessage* msg);
- void DoHandleEndUpdateStream(HostMessage* msg);
-
- // Synchronization and thread handling objects.
- MessageLoop* message_loop_;
-
- // Handles to Pepper objects needed for drawing to the screen.
- NPDevice* rendering_device_;
- NPP plugin_instance_;
+ void OnPaintDone();
+ void OnPartialDecodeDone();
+ void OnDecodeDone();
+
+ // Reference to the creating plugin instance. Needed for interacting with
+ // pepper. Marking explciitly as const since it must be initialized at
+ // object creation, and never change.
+ ChromotingPlugin* const plugin_;
+
+ pp::DeviceContext2D device_context_;
int backing_store_width_;
int backing_store_height_;
@@ -66,6 +69,10 @@ class PepperView : public ChromotingView {
bool is_static_fill_;
uint32 static_fill_color_;
+ scoped_refptr<media::VideoFrame> frame_;
+ UpdatedRects update_rects_;
+ UpdatedRects all_update_rects_;
+
scoped_ptr<Decoder> decoder_;
DISALLOW_COPY_AND_ASSIGN(PepperView);
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index d072889..bda9e60 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -71,7 +71,8 @@
'chromoting_base',
'chromoting_client',
'chromoting_jingle_glue',
- '../third_party/ppapi/ppapi.gyp:ppapi_c',
+ '../third_party/ppapi/ppapi.gyp:ppapi_cpp_objects',
+ '../third_party/zlib/zlib.gyp:zlib',
],
'sources': [
'client/plugin/chromoting_plugin.cc',
@@ -80,6 +81,8 @@
'client/plugin/pepper_entrypoints.h',
'client/plugin/pepper_view.cc',
'client/plugin/pepper_view.h',
+ 'client/plugin/pepper_util.cc',
+ 'client/plugin/pepper_util.h',
'../media/base/yuv_convert.cc',
'../media/base/yuv_convert.h',
'../media/base/yuv_row.h',