Home | History | Annotate | Download | only in pepper
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/renderer/pepper/host_globals.h"
      6 
      7 #include <limits>
      8 
      9 #include "base/command_line.h"
     10 #include "base/logging.h"
     11 #include "base/rand_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/task_runner.h"
     14 #include "content/public/common/content_switches.h"
     15 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
     16 #include "content/renderer/pepper/plugin_module.h"
     17 #include "content/renderer/render_thread_impl.h"
     18 #include "ppapi/shared_impl/api_id.h"
     19 #include "ppapi/shared_impl/id_assignment.h"
     20 #include "third_party/WebKit/public/platform/WebString.h"
     21 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
     22 #include "third_party/WebKit/public/web/WebDocument.h"
     23 #include "third_party/WebKit/public/web/WebElement.h"
     24 #include "third_party/WebKit/public/web/WebFrame.h"
     25 #include "third_party/WebKit/public/web/WebPluginContainer.h"
     26 
     27 using ppapi::CheckIdType;
     28 using ppapi::MakeTypedId;
     29 using ppapi::PPIdType;
     30 using ppapi::ResourceTracker;
     31 using WebKit::WebConsoleMessage;
     32 using WebKit::WebString;
     33 
     34 namespace content {
     35 
     36 namespace {
     37 
     38 typedef std::set<WebKit::WebPluginContainer*> ContainerSet;
     39 
     40 // Adds all WebPluginContainers associated with the given module to the set.
     41 void GetAllContainersForModule(PluginModule* module,
     42                                ContainerSet* containers) {
     43   const PluginModule::PluginInstanceSet& instances =
     44       module->GetAllInstances();
     45   for (PluginModule::PluginInstanceSet::const_iterator i = instances.begin();
     46        i != instances.end(); ++i)
     47     containers->insert((*i)->container());
     48 }
     49 
     50 WebConsoleMessage::Level LogLevelToWebLogLevel(PP_LogLevel level) {
     51   switch (level) {
     52     case PP_LOGLEVEL_TIP:
     53       return WebConsoleMessage::LevelDebug;
     54     case PP_LOGLEVEL_LOG:
     55       return WebConsoleMessage::LevelLog;
     56     case PP_LOGLEVEL_WARNING:
     57       return WebConsoleMessage::LevelWarning;
     58     case PP_LOGLEVEL_ERROR:
     59     default:
     60       return WebConsoleMessage::LevelError;
     61   }
     62 }
     63 
     64 WebConsoleMessage MakeLogMessage(PP_LogLevel level,
     65                                  const std::string& source,
     66                                  const std::string& message) {
     67   std::string result = source;
     68   if (!result.empty())
     69     result.append(": ");
     70   result.append(message);
     71   return WebConsoleMessage(LogLevelToWebLogLevel(level),
     72                            WebString(UTF8ToUTF16(result)));
     73 }
     74 
     75 }  // namespace
     76 
     77 HostGlobals* HostGlobals::host_globals_ = NULL;
     78 
     79 HostGlobals::HostGlobals()
     80     : ppapi::PpapiGlobals(),
     81       resource_tracker_(ResourceTracker::SINGLE_THREADED) {
     82   DCHECK(!host_globals_);
     83   host_globals_ = this;
     84 }
     85 
     86 HostGlobals::HostGlobals(
     87     ppapi::PpapiGlobals::PerThreadForTest per_thread_for_test)
     88     : ppapi::PpapiGlobals(per_thread_for_test),
     89       resource_tracker_(ResourceTracker::SINGLE_THREADED) {
     90   DCHECK(!host_globals_);
     91 }
     92 
     93 HostGlobals::~HostGlobals() {
     94   DCHECK(host_globals_ == this || !host_globals_);
     95   host_globals_ = NULL;
     96 }
     97 
     98 ppapi::ResourceTracker* HostGlobals::GetResourceTracker() {
     99   return &resource_tracker_;
    100 }
    101 
    102 ppapi::VarTracker* HostGlobals::GetVarTracker() {
    103   return &host_var_tracker_;
    104 }
    105 
    106 ppapi::CallbackTracker* HostGlobals::GetCallbackTrackerForInstance(
    107     PP_Instance instance) {
    108   InstanceMap::iterator found = instance_map_.find(instance);
    109   if (found == instance_map_.end())
    110     return NULL;
    111   return found->second->module()->GetCallbackTracker().get();
    112 }
    113 
    114 ppapi::thunk::PPB_Instance_API* HostGlobals::GetInstanceAPI(
    115     PP_Instance instance) {
    116   // The InstanceAPI is just implemented by the PluginInstance object.
    117   return GetInstance(instance);
    118 }
    119 
    120 ppapi::thunk::ResourceCreationAPI* HostGlobals::GetResourceCreationAPI(
    121     PP_Instance pp_instance) {
    122   PepperPluginInstanceImpl* instance = GetInstance(pp_instance);
    123   if (!instance)
    124     return NULL;
    125   return &instance->resource_creation();
    126 }
    127 
    128 PP_Module HostGlobals::GetModuleForInstance(PP_Instance instance) {
    129   PepperPluginInstanceImpl* inst = GetInstance(instance);
    130   if (!inst)
    131     return 0;
    132   return inst->module()->pp_module();
    133 }
    134 
    135 std::string HostGlobals::GetCmdLine() {
    136   return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    137       switches::kPpapiFlashArgs);
    138 }
    139 
    140 void HostGlobals::PreCacheFontForFlash(const void* logfontw) {
    141   // Not implemented in-process.
    142 }
    143 
    144 base::Lock* HostGlobals::GetProxyLock() {
    145   // We do not lock on the host side.
    146   return NULL;
    147 }
    148 
    149 void HostGlobals::LogWithSource(PP_Instance instance,
    150                                 PP_LogLevel level,
    151                                 const std::string& source,
    152                                 const std::string& value) {
    153   PepperPluginInstanceImpl* instance_object =
    154       HostGlobals::Get()->GetInstance(instance);
    155   if (instance_object) {
    156     instance_object->container()->element().document().frame()->
    157         addMessageToConsole(MakeLogMessage(level, source, value));
    158   } else {
    159     BroadcastLogWithSource(0, level, source, value);
    160   }
    161 }
    162 
    163 void HostGlobals::BroadcastLogWithSource(PP_Module pp_module,
    164                                          PP_LogLevel level,
    165                                          const std::string& source,
    166                                          const std::string& value) {
    167   // Get the unique containers associated with the broadcast. This prevents us
    168   // from sending the same message to the same console when there are two
    169   // instances on the page.
    170   ContainerSet containers;
    171   PluginModule* module = GetModule(pp_module);
    172   if (module) {
    173     GetAllContainersForModule(module, &containers);
    174   } else {
    175     // Unknown module, get containers for all modules.
    176     for (ModuleMap::const_iterator i = module_map_.begin();
    177          i != module_map_.end(); ++i) {
    178       GetAllContainersForModule(i->second, &containers);
    179     }
    180   }
    181 
    182   WebConsoleMessage message = MakeLogMessage(level, source, value);
    183   for (ContainerSet::iterator i = containers.begin();
    184        i != containers.end(); ++i)
    185      (*i)->element().document().frame()->addMessageToConsole(message);
    186 }
    187 
    188 base::TaskRunner* HostGlobals::GetFileTaskRunner(PP_Instance instance) {
    189   return RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get();
    190 }
    191 
    192 ppapi::MessageLoopShared* HostGlobals::GetCurrentMessageLoop() {
    193   return NULL;
    194 }
    195 
    196 PP_Module HostGlobals::AddModule(PluginModule* module) {
    197 #ifndef NDEBUG
    198   // Make sure we're not adding one more than once.
    199   for (ModuleMap::const_iterator i = module_map_.begin();
    200        i != module_map_.end(); ++i)
    201     DCHECK(i->second != module);
    202 #endif
    203 
    204   // See AddInstance.
    205   PP_Module new_module;
    206   do {
    207     new_module = MakeTypedId(static_cast<PP_Module>(base::RandUint64()),
    208                              ppapi::PP_ID_TYPE_MODULE);
    209   } while (!new_module ||
    210            module_map_.find(new_module) != module_map_.end());
    211   module_map_[new_module] = module;
    212   return new_module;
    213 }
    214 
    215 void HostGlobals::ModuleDeleted(PP_Module module) {
    216   DLOG_IF(ERROR, !CheckIdType(module, ppapi::PP_ID_TYPE_MODULE))
    217       << module << " is not a PP_Module.";
    218   ModuleMap::iterator found = module_map_.find(module);
    219   if (found == module_map_.end()) {
    220     NOTREACHED();
    221     return;
    222   }
    223   module_map_.erase(found);
    224 }
    225 
    226 PluginModule* HostGlobals::GetModule(PP_Module module) {
    227   DLOG_IF(ERROR, !CheckIdType(module, ppapi::PP_ID_TYPE_MODULE))
    228       << module << " is not a PP_Module.";
    229   ModuleMap::iterator found = module_map_.find(module);
    230   if (found == module_map_.end())
    231     return NULL;
    232   return found->second;
    233 }
    234 
    235 PP_Instance HostGlobals::AddInstance(PepperPluginInstanceImpl* instance) {
    236   DCHECK(instance_map_.find(instance->pp_instance()) == instance_map_.end());
    237 
    238   // Use a random number for the instance ID. This helps prevent some
    239   // accidents. See also AddModule below.
    240   //
    241   // Need to make sure the random number isn't a duplicate or 0.
    242   PP_Instance new_instance;
    243   do {
    244     new_instance = MakeTypedId(static_cast<PP_Instance>(base::RandUint64()),
    245                                ppapi::PP_ID_TYPE_INSTANCE);
    246   } while (!new_instance ||
    247            instance_map_.find(new_instance) != instance_map_.end() ||
    248            !instance->module()->ReserveInstanceID(new_instance));
    249 
    250   instance_map_[new_instance] = instance;
    251 
    252   resource_tracker_.DidCreateInstance(new_instance);
    253   return new_instance;
    254 }
    255 
    256 void HostGlobals::InstanceDeleted(PP_Instance instance) {
    257   resource_tracker_.DidDeleteInstance(instance);
    258   host_var_tracker_.DidDeleteInstance(instance);
    259   instance_map_.erase(instance);
    260 }
    261 
    262 void HostGlobals::InstanceCrashed(PP_Instance instance) {
    263   resource_tracker_.DidDeleteInstance(instance);
    264   host_var_tracker_.DidDeleteInstance(instance);
    265 }
    266 
    267 PepperPluginInstanceImpl* HostGlobals::GetInstance(PP_Instance instance) {
    268   DLOG_IF(ERROR, !CheckIdType(instance, ppapi::PP_ID_TYPE_INSTANCE))
    269       << instance << " is not a PP_Instance.";
    270   InstanceMap::iterator found = instance_map_.find(instance);
    271   if (found == instance_map_.end())
    272     return NULL;
    273   return found->second;
    274 }
    275 
    276 bool HostGlobals::IsHostGlobals() const {
    277   return true;
    278 }
    279 
    280 }  // namespace content
    281