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