summaryrefslogtreecommitdiffstats
path: root/webkit/glue/plugins/pepper_plugin_module.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/glue/plugins/pepper_plugin_module.cc')
-rw-r--r--webkit/glue/plugins/pepper_plugin_module.cc362
1 files changed, 362 insertions, 0 deletions
diff --git a/webkit/glue/plugins/pepper_plugin_module.cc b/webkit/glue/plugins/pepper_plugin_module.cc
new file mode 100644
index 0000000..8ffd78b
--- /dev/null
+++ b/webkit/glue/plugins/pepper_plugin_module.cc
@@ -0,0 +1,362 @@
+// 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 "webkit/glue/plugins/pepper_plugin_module.h"
+
+#include <set>
+
+#include "base/command_line.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "third_party/ppapi/c/ppb_buffer.h"
+#include "third_party/ppapi/c/ppb_core.h"
+#include "third_party/ppapi/c/ppb_device_context_2d.h"
+#include "third_party/ppapi/c/ppb_file_io.h"
+#include "third_party/ppapi/c/ppb_file_io_trusted.h"
+#include "third_party/ppapi/c/ppb_file_system.h"
+#include "third_party/ppapi/c/ppb_image_data.h"
+#include "third_party/ppapi/c/ppb_instance.h"
+#include "third_party/ppapi/c/ppb_find.h"
+#include "third_party/ppapi/c/ppb_font.h"
+#include "third_party/ppapi/c/ppb_scrollbar.h"
+#include "third_party/ppapi/c/ppb_testing.h"
+#include "third_party/ppapi/c/ppb_url_loader.h"
+#include "third_party/ppapi/c/ppb_url_request_info.h"
+#include "third_party/ppapi/c/ppb_url_response_info.h"
+#include "third_party/ppapi/c/ppb_var.h"
+#include "third_party/ppapi/c/ppb_widget.h"
+#include "third_party/ppapi/c/ppp.h"
+#include "third_party/ppapi/c/ppp_instance.h"
+#include "third_party/ppapi/c/pp_module.h"
+#include "third_party/ppapi/c/pp_resource.h"
+#include "third_party/ppapi/c/pp_var.h"
+#include "webkit/glue/plugins/pepper_buffer.h"
+#include "webkit/glue/plugins/pepper_device_context_2d.h"
+#include "webkit/glue/plugins/pepper_directory_reader.h"
+#include "webkit/glue/plugins/pepper_file_io.h"
+#include "webkit/glue/plugins/pepper_file_ref.h"
+#include "webkit/glue/plugins/pepper_file_system.h"
+#include "webkit/glue/plugins/pepper_font.h"
+#include "webkit/glue/plugins/pepper_image_data.h"
+#include "webkit/glue/plugins/pepper_plugin_instance.h"
+#include "webkit/glue/plugins/pepper_private.h"
+#include "webkit/glue/plugins/pepper_resource_tracker.h"
+#include "webkit/glue/plugins/pepper_scrollbar.h"
+#include "webkit/glue/plugins/pepper_url_loader.h"
+#include "webkit/glue/plugins/pepper_url_request_info.h"
+#include "webkit/glue/plugins/pepper_url_response_info.h"
+#include "webkit/glue/plugins/pepper_var.h"
+#include "webkit/glue/plugins/pepper_widget.h"
+#include "webkit/glue/plugins/ppb_private.h"
+
+namespace pepper {
+
+namespace {
+
+// Maintains all currently loaded plugin libs for validating PP_Module
+// identifiers.
+typedef std::set<PluginModule*> PluginModuleSet;
+
+PluginModuleSet* GetLivePluginSet() {
+ static PluginModuleSet live_plugin_libs;
+ return &live_plugin_libs;
+}
+
+base::MessageLoopProxy* GetMainThreadMessageLoop() {
+ static scoped_refptr<base::MessageLoopProxy> proxy(
+ base::MessageLoopProxy::CreateForCurrentThread());
+ return proxy.get();
+}
+
+// PPB_Core --------------------------------------------------------------------
+
+void AddRefResource(PP_Resource resource) {
+ if (!ResourceTracker::Get()->AddRefResource(resource)) {
+ DLOG(WARNING) << "AddRefResource()ing a nonexistent resource";
+ }
+}
+
+void ReleaseResource(PP_Resource resource) {
+ if (!ResourceTracker::Get()->UnrefResource(resource)) {
+ DLOG(WARNING) << "ReleaseResource()ing a nonexistent resource";
+ }
+}
+
+void* MemAlloc(size_t num_bytes) {
+ return malloc(num_bytes);
+}
+
+void MemFree(void* ptr) {
+ free(ptr);
+}
+
+double GetTime() {
+ return base::Time::Now().ToDoubleT();
+}
+
+void CallOnMainThread(int delay_in_msec,
+ PP_CompletionCallback callback,
+ int32_t result) {
+ GetMainThreadMessageLoop()->PostDelayedTask(
+ FROM_HERE,
+ NewRunnableFunction(callback.func, callback.user_data, result),
+ delay_in_msec);
+}
+
+const PPB_Core core_interface = {
+ &AddRefResource,
+ &ReleaseResource,
+ &MemAlloc,
+ &MemFree,
+ &GetTime,
+ &CallOnMainThread
+};
+
+// PPB_Testing -----------------------------------------------------------------
+
+bool ReadImageData(PP_Resource device_context_2d,
+ PP_Resource image,
+ const PP_Point* top_left) {
+ scoped_refptr<DeviceContext2D> context(
+ Resource::GetAs<DeviceContext2D>(device_context_2d));
+ if (!context.get())
+ return false;
+ return context->ReadImageData(image, top_left);
+}
+
+void RunMessageLoop() {
+ bool old_state = MessageLoop::current()->NestableTasksAllowed();
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ MessageLoop::current()->Run();
+ MessageLoop::current()->SetNestableTasksAllowed(old_state);
+}
+
+void QuitMessageLoop() {
+ MessageLoop::current()->Quit();
+}
+
+const PPB_Testing testing_interface = {
+ &ReadImageData,
+ &RunMessageLoop,
+ &QuitMessageLoop,
+};
+
+// GetInterface ----------------------------------------------------------------
+
+const void* GetInterface(const char* name) {
+ if (strcmp(name, PPB_CORE_INTERFACE) == 0)
+ return &core_interface;
+ if (strcmp(name, PPB_VAR_INTERFACE) == 0)
+ return GetVarInterface();
+ if (strcmp(name, PPB_INSTANCE_INTERFACE) == 0)
+ return PluginInstance::GetInterface();
+ if (strcmp(name, PPB_IMAGEDATA_INTERFACE) == 0)
+ return ImageData::GetInterface();
+ if (strcmp(name, PPB_DEVICECONTEXT2D_INTERFACE) == 0)
+ return DeviceContext2D::GetInterface();
+ if (strcmp(name, PPB_URLLOADER_INTERFACE) == 0)
+ return URLLoader::GetInterface();
+ if (strcmp(name, PPB_URLREQUESTINFO_INTERFACE) == 0)
+ return URLRequestInfo::GetInterface();
+ if (strcmp(name, PPB_URLRESPONSEINFO_INTERFACE) == 0)
+ return URLResponseInfo::GetInterface();
+ if (strcmp(name, PPB_BUFFER_INTERFACE) == 0)
+ return Buffer::GetInterface();
+ if (strcmp(name, PPB_FILEREF_INTERFACE) == 0)
+ return FileRef::GetInterface();
+ if (strcmp(name, PPB_FILEIO_INTERFACE) == 0)
+ return FileIO::GetInterface();
+ if (strcmp(name, PPB_FILEIOTRUSTED_INTERFACE) == 0)
+ return FileIO::GetTrustedInterface();
+ if (strcmp(name, PPB_FILESYSTEM_INTERFACE) == 0)
+ return FileSystem::GetInterface();
+ if (strcmp(name, PPB_DIRECTORYREADER_INTERFACE) == 0)
+ return DirectoryReader::GetInterface();
+ if (strcmp(name, PPB_WIDGET_INTERFACE) == 0)
+ return Widget::GetInterface();
+ if (strcmp(name, PPB_SCROLLBAR_INTERFACE) == 0)
+ return Scrollbar::GetInterface();
+ if (strcmp(name, PPB_FONT_INTERFACE) == 0)
+ return Font::GetInterface();
+ if (strcmp(name, PPB_FIND_INTERFACE) == 0)
+ return PluginInstance::GetFindInterface();
+ if (strcmp(name, PPB_PRIVATE_INTERFACE) == 0)
+ return Private::GetInterface();
+
+ // Only support the testing interface when the command line switch is
+ // specified. This allows us to prevent people from (ab)using this interface
+ // in production code.
+ if (strcmp(name, PPB_TESTING_INTERFACE) == 0) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch("enable-pepper-testing"))
+ return &testing_interface;
+ }
+ return NULL;
+}
+
+} // namespace
+
+PluginModule::PluginModule()
+ : initialized_(false),
+ library_(NULL) {
+ GetMainThreadMessageLoop(); // Initialize the main thread message loop.
+ GetLivePluginSet()->insert(this);
+}
+
+PluginModule::~PluginModule() {
+ // When the module is being deleted, there should be no more instances still
+ // holding a reference to us.
+ DCHECK(instances_.empty());
+
+ GetLivePluginSet()->erase(this);
+
+ if (entry_points_.shutdown_module)
+ entry_points_.shutdown_module();
+
+ if (library_)
+ base::UnloadNativeLibrary(library_);
+}
+
+// static
+scoped_refptr<PluginModule> PluginModule::CreateModule(
+ const FilePath& path) {
+ // FIXME(brettw) do uniquifying of the plugin here like the NPAPI one.
+
+ scoped_refptr<PluginModule> lib(new PluginModule());
+ if (!lib->InitFromFile(path))
+ return NULL;
+
+ return lib;
+}
+
+scoped_refptr<PluginModule> PluginModule::CreateInternalModule(
+ EntryPoints entry_points) {
+ scoped_refptr<PluginModule> lib(new PluginModule());
+ if (!lib->InitFromEntryPoints(entry_points))
+ return NULL;
+
+ return lib;
+}
+
+// static
+PluginModule* PluginModule::FromPPModule(PP_Module module) {
+ PluginModule* lib = reinterpret_cast<PluginModule*>(module);
+ if (GetLivePluginSet()->find(lib) == GetLivePluginSet()->end())
+ return NULL; // Invalid plugin.
+ return lib;
+}
+
+// static
+const PPB_Core* PluginModule::GetCore() {
+ return &core_interface;
+}
+
+bool PluginModule::InitFromEntryPoints(const EntryPoints& entry_points) {
+ if (initialized_)
+ return true;
+
+ // Attempt to run the initialization funciton.
+ int retval = entry_points.initialize_module(GetPPModule(), &GetInterface);
+ if (retval != 0) {
+ LOG(WARNING) << "PPP_InitializeModule returned failure " << retval;
+ return false;
+ }
+
+ entry_points_ = entry_points;
+ initialized_ = true;
+ return true;
+}
+
+bool PluginModule::InitFromFile(const FilePath& path) {
+ if (initialized_)
+ return true;
+
+ base::NativeLibrary library = base::LoadNativeLibrary(path);
+ if (!library)
+ return false;
+
+ EntryPoints entry_points;
+ if (!LoadEntryPoints(library, &entry_points) ||
+ !InitFromEntryPoints(entry_points)) {
+ base::UnloadNativeLibrary(library);
+ return false;
+ }
+
+ // We let InitFromEntryPoints() handle setting the all the internal state
+ // of the object other than the |library_| reference.
+ library_ = library;
+ return true;
+}
+
+// static
+bool PluginModule::LoadEntryPoints(const base::NativeLibrary& library,
+ EntryPoints* entry_points) {
+
+ entry_points->get_interface =
+ reinterpret_cast<PPP_GetInterfaceFunc>(
+ base::GetFunctionPointerFromNativeLibrary(library,
+ "PPP_GetInterface"));
+ if (!entry_points->get_interface) {
+ LOG(WARNING) << "No PPP_GetInterface in plugin library";
+ return false;
+ }
+
+ entry_points->initialize_module =
+ reinterpret_cast<PPP_InitializeModuleFunc>(
+ base::GetFunctionPointerFromNativeLibrary(library,
+ "PPP_InitializeModule"));
+ if (!entry_points->initialize_module) {
+ LOG(WARNING) << "No PPP_InitializeModule in plugin library";
+ return false;
+ }
+
+ // It's okay for PPP_ShutdownModule to not be defined and shutdown_module to
+ // be NULL.
+ entry_points->shutdown_module =
+ reinterpret_cast<PPP_ShutdownModuleFunc>(
+ base::GetFunctionPointerFromNativeLibrary(library,
+ "PPP_ShutdownModule"));
+
+ return true;
+}
+
+PP_Module PluginModule::GetPPModule() const {
+ return reinterpret_cast<intptr_t>(this);
+}
+
+PluginInstance* PluginModule::CreateInstance(PluginDelegate* delegate) {
+ const PPP_Instance* plugin_instance_interface =
+ reinterpret_cast<const PPP_Instance*>(GetPluginInterface(
+ PPP_INSTANCE_INTERFACE));
+ if (!plugin_instance_interface) {
+ LOG(WARNING) << "Plugin doesn't support instance interface, failing.";
+ return NULL;
+ }
+ return new PluginInstance(delegate, this, plugin_instance_interface);
+}
+
+PluginInstance* PluginModule::GetSomeInstance() const {
+ // This will generally crash later if there is not actually any instance to
+ // return, so we force a crash now to make bugs easier to track down.
+ CHECK(!instances_.empty());
+ return *instances_.begin();
+}
+
+const void* PluginModule::GetPluginInterface(const char* name) const {
+ if (!entry_points_.get_interface)
+ return NULL;
+ return entry_points_.get_interface(name);
+}
+
+void PluginModule::InstanceCreated(PluginInstance* instance) {
+ instances_.insert(instance);
+}
+
+void PluginModule::InstanceDeleted(PluginInstance* instance) {
+ instances_.erase(instance);
+}
+
+} // namespace pepper