diff options
-rw-r--r-- | remoting/client/chromoting_client.cc | 10 | ||||
-rw-r--r-- | remoting/client/chromoting_client.h | 4 | ||||
-rw-r--r-- | remoting/client/plugin/chromoting_plugin.cc | 82 | ||||
-rw-r--r-- | remoting/client/plugin/chromoting_plugin.h | 38 | ||||
-rw-r--r-- | remoting/client/plugin/pepper_entrypoints.cc | 235 | ||||
-rw-r--r-- | remoting/client/plugin/pepper_util.cc | 31 | ||||
-rw-r--r-- | remoting/client/plugin/pepper_util.h | 32 | ||||
-rw-r--r-- | remoting/client/plugin/pepper_view.cc | 234 | ||||
-rw-r--r-- | remoting/client/plugin/pepper_view.h | 51 | ||||
-rw-r--r-- | remoting/remoting.gyp | 5 |
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', |