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.
5 #include "content/renderer/pepper/host_globals.h"
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"
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
;
41 typedef std::set
<WebPluginContainer
*> ContainerSet
;
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();
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.
54 containers
->insert(container
);
58 WebConsoleMessage::Level
LogLevelToWebLogLevel(PP_LogLevel level
) {
61 return WebConsoleMessage::LevelDebug
;
63 return WebConsoleMessage::LevelLog
;
64 case PP_LOGLEVEL_WARNING
:
65 return WebConsoleMessage::LevelWarning
;
66 case PP_LOGLEVEL_ERROR
:
68 return WebConsoleMessage::LevelError
;
72 WebConsoleMessage
MakeLogMessage(PP_LogLevel level
,
73 const std::string
& source
,
74 const std::string
& message
) {
75 std::string result
= source
;
78 result
.append(message
);
79 return WebConsoleMessage(LogLevelToWebLogLevel(level
),
80 WebString(base::UTF8ToUTF16(result
)));
85 HostGlobals
* HostGlobals::host_globals_
= NULL
;
87 HostGlobals::HostGlobals()
88 : ppapi::PpapiGlobals(),
89 resource_tracker_(ResourceTracker::SINGLE_THREADED
) {
90 DCHECK(!host_globals_
);
92 // We do not support calls off of the main thread on the host side, and thus
94 ppapi::ProxyLock::DisableLocking();
97 HostGlobals::~HostGlobals() {
98 DCHECK(host_globals_
== this || !host_globals_
);
102 ppapi::ResourceTracker
* HostGlobals::GetResourceTracker() {
103 return &resource_tracker_
;
106 ppapi::VarTracker
* HostGlobals::GetVarTracker() { return &host_var_tracker_
; }
108 ppapi::CallbackTracker
* HostGlobals::GetCallbackTrackerForInstance(
109 PP_Instance instance
) {
110 InstanceMap::iterator found
= instance_map_
.find(instance
);
111 if (found
== instance_map_
.end())
113 return found
->second
->module()->GetCallbackTracker().get();
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
);
122 ppapi::thunk::ResourceCreationAPI
* HostGlobals::GetResourceCreationAPI(
123 PP_Instance pp_instance
) {
124 PepperPluginInstanceImpl
* instance
= GetInstance(pp_instance
);
127 return &instance
->resource_creation();
130 PP_Module
HostGlobals::GetModuleForInstance(PP_Instance instance
) {
131 PepperPluginInstanceImpl
* inst
= GetInstance(instance
);
134 return inst
->module()->pp_module();
137 std::string
HostGlobals::GetCmdLine() {
138 return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
139 switches::kPpapiFlashArgs
);
142 void HostGlobals::PreCacheFontForFlash(const void* logfontw
) {
143 // Not implemented in-process.
146 void HostGlobals::LogWithSource(PP_Instance instance
,
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()
157 ->addMessageToConsole(MakeLogMessage(level
, source
, value
));
159 BroadcastLogWithSource(0, level
, source
, value
);
163 void HostGlobals::BroadcastLogWithSource(PP_Module pp_module
,
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
);
173 GetAllContainersForModule(module
, &containers
);
175 // Unknown module, get containers for all modules.
176 for (ModuleMap::const_iterator i
= module_map_
.begin();
177 i
!= module_map_
.end();
179 GetAllContainersForModule(i
->second
, &containers
);
183 WebConsoleMessage message
= MakeLogMessage(level
, source
, value
);
184 for (ContainerSet::iterator i
= containers
.begin(); i
!= containers
.end();
186 WebLocalFrame
* frame
= (*i
)->element().document().frame();
188 frame
->addMessageToConsole(message
);
192 base::TaskRunner
* HostGlobals::GetFileTaskRunner() {
193 return RenderThreadImpl::current()->GetFileThreadMessageLoopProxy().get();
196 ppapi::MessageLoopShared
* HostGlobals::GetCurrentMessageLoop() { return NULL
; }
198 PP_Module
HostGlobals::AddModule(PluginModule
* module
) {
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();
204 DCHECK(i
->second
!= module
);
208 PP_Module new_module
;
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
;
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()) {
225 module_map_
.erase(found
);
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())
234 return found
->second
;
237 PP_Instance
HostGlobals::AddInstance(PepperPluginInstanceImpl
* instance
) {
238 DCHECK(instance_map_
.find(instance
->pp_instance()) == instance_map_
.end());
240 // Use a random number for the instance ID. This helps prevent some
241 // accidents. See also AddModule below.
243 // Need to make sure the random number isn't a duplicate or 0.
244 PP_Instance new_instance
;
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
));
252 instance_map_
[new_instance
] = instance
;
254 resource_tracker_
.DidCreateInstance(new_instance
);
258 void HostGlobals::InstanceDeleted(PP_Instance instance
) {
259 resource_tracker_
.DidDeleteInstance(instance
);
260 host_var_tracker_
.DidDeleteInstance(instance
);
261 instance_map_
.erase(instance
);
264 void HostGlobals::InstanceCrashed(PP_Instance instance
) {
265 resource_tracker_
.DidDeleteInstance(instance
);
266 host_var_tracker_
.DidDeleteInstance(instance
);
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())
275 return found
->second
;
278 bool HostGlobals::IsHostGlobals() const { return true; }
280 } // namespace content