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