1 // Copyright 2013 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/resource_converter.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/public/renderer/renderer_ppapi_host.h"
10 #include "content/renderer/pepper/pepper_file_system_host.h"
11 #include "content/renderer/pepper/pepper_media_stream_audio_track_host.h"
12 #include "content/renderer/pepper/pepper_media_stream_video_track_host.h"
13 #include "ipc/ipc_message.h"
14 #include "ppapi/host/ppapi_host.h"
15 #include "ppapi/host/resource_host.h"
16 #include "ppapi/proxy/ppapi_messages.h"
17 #include "ppapi/shared_impl/resource_var.h"
18 #include "ppapi/shared_impl/scoped_pp_var.h"
19 #include "third_party/WebKit/public/platform/WebFileSystem.h"
20 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
21 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
22 #include "third_party/WebKit/public/web/WebDOMFileSystem.h"
23 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h"
24 #include "third_party/WebKit/public/web/WebLocalFrame.h"
25 #include "webkit/common/fileapi/file_system_util.h"
27 using ppapi::ResourceVar
;
33 const base::Callback
<void(bool)>& callback
,
34 const std::vector
<scoped_refptr
<content::HostResourceVar
> >& browser_vars
,
35 const std::vector
<int>& pending_host_ids
) {
36 CHECK(browser_vars
.size() == pending_host_ids
.size());
37 for (size_t i
= 0; i
< browser_vars
.size(); ++i
) {
38 browser_vars
[i
]->set_pending_browser_host_id(pending_host_ids
[i
]);
43 // Converts a blink::WebFileSystem::Type to a PP_FileSystemType.
44 PP_FileSystemType
WebFileSystemTypeToPPAPI(blink::WebFileSystem::Type type
) {
46 case blink::WebFileSystem::TypeTemporary
:
47 return PP_FILESYSTEMTYPE_LOCALTEMPORARY
;
48 case blink::WebFileSystem::TypePersistent
:
49 return PP_FILESYSTEMTYPE_LOCALPERSISTENT
;
50 case blink::WebFileSystem::TypeIsolated
:
51 return PP_FILESYSTEMTYPE_ISOLATED
;
52 case blink::WebFileSystem::TypeExternal
:
53 return PP_FILESYSTEMTYPE_EXTERNAL
;
56 return PP_FILESYSTEMTYPE_LOCALTEMPORARY
;
60 // Converts a storage::FileSystemType to a blink::WebFileSystemType.
61 // Returns true on success, false if |type| does not correspond to a
63 bool FileApiFileSystemTypeToWebFileSystemType(
64 storage::FileSystemType type
,
65 blink::WebFileSystemType
* result_type
) {
67 case storage::kFileSystemTypeTemporary
:
68 *result_type
= blink::WebFileSystemTypeTemporary
;
70 case storage::kFileSystemTypePersistent
:
71 *result_type
= blink::WebFileSystemTypePersistent
;
73 case storage::kFileSystemTypeIsolated
:
74 *result_type
= blink::WebFileSystemTypeIsolated
;
76 case storage::kFileSystemTypeExternal
:
77 *result_type
= blink::WebFileSystemTypeExternal
;
84 // Given a V8 value containing a DOMFileSystem, creates a resource host and
85 // returns the resource information for serialization.
87 bool DOMFileSystemToResource(
89 RendererPpapiHost
* host
,
90 const blink::WebDOMFileSystem
& dom_file_system
,
91 int* pending_renderer_id
,
92 scoped_ptr
<IPC::Message
>* create_message
,
93 scoped_ptr
<IPC::Message
>* browser_host_create_message
) {
94 DCHECK(!dom_file_system
.isNull());
96 PP_FileSystemType file_system_type
=
97 WebFileSystemTypeToPPAPI(dom_file_system
.type());
98 GURL root_url
= dom_file_system
.rootURL();
100 // Raw external file system access is not allowed, but external file system
101 // access through fileapi is allowed. (Without this check, there would be a
102 // CHECK failure in FileRefResource.)
103 if ((file_system_type
== PP_FILESYSTEMTYPE_EXTERNAL
) &&
104 (!root_url
.is_valid())) {
108 *pending_renderer_id
= host
->GetPpapiHost()->AddPendingResourceHost(
109 scoped_ptr
<ppapi::host::ResourceHost
>(new PepperFileSystemHost(
110 host
, instance
, 0, root_url
, file_system_type
)));
111 if (*pending_renderer_id
== 0)
114 create_message
->reset(
115 new PpapiPluginMsg_FileSystem_CreateFromPendingHost(file_system_type
));
117 browser_host_create_message
->reset(
118 new PpapiHostMsg_FileSystem_CreateFromRenderer(root_url
.spec(),
123 bool ResourceHostToDOMFileSystem(
124 content::PepperFileSystemHost
* file_system_host
,
125 v8::Handle
<v8::Context
> context
,
126 v8::Handle
<v8::Value
>* dom_file_system
) {
127 GURL root_url
= file_system_host
->GetRootUrl();
129 storage::FileSystemType type
;
130 base::FilePath virtual_path
;
131 storage::ParseFileSystemSchemeURL(root_url
, &origin
, &type
, &virtual_path
);
133 std::string name
= storage::GetFileSystemName(origin
, type
);
134 blink::WebFileSystemType blink_type
;
135 if (!FileApiFileSystemTypeToWebFileSystemType(type
, &blink_type
))
137 blink::WebLocalFrame
* frame
= blink::WebLocalFrame::frameForContext(context
);
138 blink::WebDOMFileSystem web_dom_file_system
= blink::WebDOMFileSystem::create(
141 blink::WebString::fromUTF8(name
),
143 blink::WebDOMFileSystem::SerializableTypeSerializable
);
145 web_dom_file_system
.toV8Value(context
->Global(), context
->GetIsolate());
149 bool ResourceHostToDOMMediaStreamVideoTrack(
150 content::PepperMediaStreamVideoTrackHost
* host
,
151 v8::Handle
<v8::Context
> context
,
152 v8::Handle
<v8::Value
>* dom_video_track
) {
153 // TODO(ronghuawu): Implement this once crbug/352219 is resolved.
154 // blink::WebMediaStreamTrack track = host->track();
155 // *dom_video_track = track.toV8Value();
159 bool DOMMediaStreamTrackToResource(
160 PP_Instance instance
,
161 RendererPpapiHost
* host
,
162 const blink::WebDOMMediaStreamTrack
& dom_media_stream_track
,
163 int* pending_renderer_id
,
164 scoped_ptr
<IPC::Message
>* create_message
) {
165 DCHECK(!dom_media_stream_track
.isNull());
166 *pending_renderer_id
= 0;
167 #if defined(ENABLE_WEBRTC)
168 const blink::WebMediaStreamTrack track
= dom_media_stream_track
.component();
169 const std::string id
= track
.source().id().utf8();
171 if (track
.source().type() == blink::WebMediaStreamSource::TypeVideo
) {
172 *pending_renderer_id
= host
->GetPpapiHost()->AddPendingResourceHost(
173 scoped_ptr
<ppapi::host::ResourceHost
>(
174 new PepperMediaStreamVideoTrackHost(host
, instance
, 0, track
)));
175 if (*pending_renderer_id
== 0)
178 create_message
->reset(
179 new PpapiPluginMsg_MediaStreamVideoTrack_CreateFromPendingHost(id
));
181 } else if (track
.source().type() == blink::WebMediaStreamSource::TypeAudio
) {
182 *pending_renderer_id
= host
->GetPpapiHost()->AddPendingResourceHost(
183 scoped_ptr
<ppapi::host::ResourceHost
>(
184 new PepperMediaStreamAudioTrackHost(host
, instance
, 0, track
)));
185 if (*pending_renderer_id
== 0)
188 create_message
->reset(
189 new PpapiPluginMsg_MediaStreamAudioTrack_CreateFromPendingHost(id
));
198 ResourceConverter::~ResourceConverter() {}
200 ResourceConverterImpl::ResourceConverterImpl(PP_Instance instance
,
201 RendererPpapiHost
* host
)
202 : instance_(instance
), host_(host
) {}
204 ResourceConverterImpl::~ResourceConverterImpl() {
205 // Verify Flush() was called.
206 DCHECK(browser_host_create_messages_
.empty());
207 DCHECK(browser_vars_
.empty());
210 bool ResourceConverterImpl::FromV8Value(v8::Handle
<v8::Object
> val
,
211 v8::Handle
<v8::Context
> context
,
213 bool* was_resource
) {
214 v8::Context::Scope
context_scope(context
);
215 v8::HandleScope
handle_scope(context
->GetIsolate());
217 *was_resource
= false;
219 blink::WebDOMFileSystem dom_file_system
=
220 blink::WebDOMFileSystem::fromV8Value(val
);
221 if (!dom_file_system
.isNull()) {
222 int pending_renderer_id
;
223 scoped_ptr
<IPC::Message
> create_message
;
224 scoped_ptr
<IPC::Message
> browser_host_create_message
;
225 if (!DOMFileSystemToResource(instance_
,
228 &pending_renderer_id
,
230 &browser_host_create_message
)) {
233 DCHECK(create_message
);
234 DCHECK(browser_host_create_message
);
235 scoped_refptr
<HostResourceVar
> result_var
=
236 CreateResourceVarWithBrowserHost(
237 pending_renderer_id
, *create_message
, *browser_host_create_message
);
238 *result
= result_var
->GetPPVar();
239 *was_resource
= true;
243 blink::WebDOMMediaStreamTrack dom_media_stream_track
=
244 blink::WebDOMMediaStreamTrack::fromV8Value(val
);
245 if (!dom_media_stream_track
.isNull()) {
246 int pending_renderer_id
;
247 scoped_ptr
<IPC::Message
> create_message
;
248 if (!DOMMediaStreamTrackToResource(instance_
,
250 dom_media_stream_track
,
251 &pending_renderer_id
,
255 DCHECK(create_message
);
256 scoped_refptr
<HostResourceVar
> result_var
=
257 CreateResourceVar(pending_renderer_id
, *create_message
);
258 *result
= result_var
->GetPPVar();
259 *was_resource
= true;
263 // The value was not convertible to a resource. Return true with
264 // |was_resource| set to false. As per the interface of FromV8Value, |result|
265 // may be left unmodified in this case.
269 void ResourceConverterImpl::Reset() {
270 browser_host_create_messages_
.clear();
271 browser_vars_
.clear();
274 bool ResourceConverterImpl::NeedsFlush() {
275 return !browser_host_create_messages_
.empty();
278 void ResourceConverterImpl::Flush(const base::Callback
<void(bool)>& callback
) {
279 host_
->CreateBrowserResourceHosts(
281 browser_host_create_messages_
,
282 base::Bind(&FlushComplete
, callback
, browser_vars_
));
283 browser_host_create_messages_
.clear();
284 browser_vars_
.clear();
287 bool ResourceConverterImpl::ToV8Value(const PP_Var
& var
,
288 v8::Handle
<v8::Context
> context
,
289 v8::Handle
<v8::Value
>* result
) {
290 DCHECK(var
.type
== PP_VARTYPE_RESOURCE
);
292 ResourceVar
* resource
= ResourceVar::FromPPVar(var
);
297 PP_Resource resource_id
= resource
->GetPPResource();
299 // Get the renderer-side resource host for this resource.
300 content::RendererPpapiHost
* renderer_ppapi_host
=
301 content::RendererPpapiHost::GetForPPInstance(instance_
);
302 if (!renderer_ppapi_host
) {
303 // This should never happen: the RendererPpapiHost is owned by the module
304 // and should outlive instances associated with it. However, if it doesn't
305 // for some reason, we do not want to crash.
309 ::ppapi::host::PpapiHost
* ppapi_host
= renderer_ppapi_host
->GetPpapiHost();
310 ::ppapi::host::ResourceHost
* resource_host
=
311 ppapi_host
->GetResourceHost(resource_id
);
312 if (resource_host
== NULL
) {
313 LOG(ERROR
) << "No resource host for resource #" << resource_id
;
317 // Convert to the appropriate type of resource host.
318 if (resource_host
->IsFileSystemHost()) {
319 return ResourceHostToDOMFileSystem(
320 static_cast<content::PepperFileSystemHost
*>(resource_host
),
323 } else if (resource_host
->IsMediaStreamVideoTrackHost()) {
324 return ResourceHostToDOMMediaStreamVideoTrack(
325 static_cast<content::PepperMediaStreamVideoTrackHost
*>(resource_host
),
329 LOG(ERROR
) << "The type of resource #" << resource_id
330 << " cannot be converted to a JavaScript object.";
335 scoped_refptr
<HostResourceVar
> ResourceConverterImpl::CreateResourceVar(
336 int pending_renderer_id
,
337 const IPC::Message
& create_message
) {
338 return new HostResourceVar(pending_renderer_id
, create_message
);
341 scoped_refptr
<HostResourceVar
>
342 ResourceConverterImpl::CreateResourceVarWithBrowserHost(
343 int pending_renderer_id
,
344 const IPC::Message
& create_message
,
345 const IPC::Message
& browser_host_create_message
) {
346 scoped_refptr
<HostResourceVar
> result
=
347 CreateResourceVar(pending_renderer_id
, create_message
);
348 browser_host_create_messages_
.push_back(browser_host_create_message
);
349 browser_vars_
.push_back(result
);
353 } // namespace content