Upstream version 7.36.149.0
[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/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