- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / host_globals.cc
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 WebKit::WebConsoleMessage;
33 using WebKit::WebString;
34
35 namespace content {
36
37 namespace {
38
39 typedef std::set<WebKit::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