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. 4 5 #include "content/renderer/pepper/resource_converter.h" 6 7 #include "base/bind.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 "storage/common/fileapi/file_system_util.h" 20 #include "third_party/WebKit/public/platform/WebFileSystem.h" 21 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" 22 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" 23 #include "third_party/WebKit/public/web/WebDOMFileSystem.h" 24 #include "third_party/WebKit/public/web/WebDOMMediaStreamTrack.h" 25 #include "third_party/WebKit/public/web/WebLocalFrame.h" 26 27 using ppapi::ResourceVar; 28 29 namespace content { 30 namespace { 31 32 void FlushComplete( 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]); 39 } 40 callback.Run(true); 41 } 42 43 // Converts a blink::WebFileSystem::Type to a PP_FileSystemType. 44 PP_FileSystemType WebFileSystemTypeToPPAPI(blink::WebFileSystem::Type type) { 45 switch (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; 54 default: 55 NOTREACHED(); 56 return PP_FILESYSTEMTYPE_LOCALTEMPORARY; 57 } 58 } 59 60 // Converts a storage::FileSystemType to a blink::WebFileSystemType. 61 // Returns true on success, false if |type| does not correspond to a 62 // WebFileSystemType. 63 bool FileApiFileSystemTypeToWebFileSystemType( 64 storage::FileSystemType type, 65 blink::WebFileSystemType* result_type) { 66 switch (type) { 67 case storage::kFileSystemTypeTemporary: 68 *result_type = blink::WebFileSystemTypeTemporary; 69 return true; 70 case storage::kFileSystemTypePersistent: 71 *result_type = blink::WebFileSystemTypePersistent; 72 return true; 73 case storage::kFileSystemTypeIsolated: 74 *result_type = blink::WebFileSystemTypeIsolated; 75 return true; 76 case storage::kFileSystemTypeExternal: 77 *result_type = blink::WebFileSystemTypeExternal; 78 return true; 79 default: 80 return false; 81 } 82 } 83 84 // Given a V8 value containing a DOMFileSystem, creates a resource host and 85 // returns the resource information for serialization. 86 // On error, false. 87 bool DOMFileSystemToResource( 88 PP_Instance instance, 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()); 95 96 PP_FileSystemType file_system_type = 97 WebFileSystemTypeToPPAPI(dom_file_system.type()); 98 GURL root_url = dom_file_system.rootURL(); 99 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())) { 105 return false; 106 } 107 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) 112 return false; 113 114 create_message->reset( 115 new PpapiPluginMsg_FileSystem_CreateFromPendingHost(file_system_type)); 116 117 browser_host_create_message->reset( 118 new PpapiHostMsg_FileSystem_CreateFromRenderer(root_url.spec(), 119 file_system_type)); 120 return true; 121 } 122 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(); 128 GURL origin; 129 storage::FileSystemType type; 130 base::FilePath virtual_path; 131 storage::ParseFileSystemSchemeURL(root_url, &origin, &type, &virtual_path); 132 133 std::string name = storage::GetFileSystemName(origin, type); 134 blink::WebFileSystemType blink_type; 135 if (!FileApiFileSystemTypeToWebFileSystemType(type, &blink_type)) 136 return false; 137 blink::WebLocalFrame* frame = blink::WebLocalFrame::frameForContext(context); 138 blink::WebDOMFileSystem web_dom_file_system = blink::WebDOMFileSystem::create( 139 frame, 140 blink_type, 141 blink::WebString::fromUTF8(name), 142 root_url, 143 blink::WebDOMFileSystem::SerializableTypeSerializable); 144 *dom_file_system = 145 web_dom_file_system.toV8Value(context->Global(), context->GetIsolate()); 146 return true; 147 } 148 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(); 156 return false; 157 } 158 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(); 170 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) 176 return false; 177 178 create_message->reset( 179 new PpapiPluginMsg_MediaStreamVideoTrack_CreateFromPendingHost(id)); 180 return true; 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) 186 return false; 187 188 create_message->reset( 189 new PpapiPluginMsg_MediaStreamAudioTrack_CreateFromPendingHost(id)); 190 return true; 191 } 192 #endif 193 return false; 194 } 195 196 } // namespace 197 198 ResourceConverter::~ResourceConverter() {} 199 200 ResourceConverterImpl::ResourceConverterImpl(PP_Instance instance, 201 RendererPpapiHost* host) 202 : instance_(instance), host_(host) {} 203 204 ResourceConverterImpl::~ResourceConverterImpl() { 205 // Verify Flush() was called. 206 DCHECK(browser_host_create_messages_.empty()); 207 DCHECK(browser_vars_.empty()); 208 } 209 210 bool ResourceConverterImpl::FromV8Value(v8::Handle<v8::Object> val, 211 v8::Handle<v8::Context> context, 212 PP_Var* result, 213 bool* was_resource) { 214 v8::Context::Scope context_scope(context); 215 v8::HandleScope handle_scope(context->GetIsolate()); 216 217 *was_resource = false; 218 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_, 226 host_, 227 dom_file_system, 228 &pending_renderer_id, 229 &create_message, 230 &browser_host_create_message)) { 231 return false; 232 } 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; 240 return true; 241 } 242 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_, 249 host_, 250 dom_media_stream_track, 251 &pending_renderer_id, 252 &create_message)) { 253 return false; 254 } 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; 260 return true; 261 } 262 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. 266 return true; 267 } 268 269 void ResourceConverterImpl::Reset() { 270 browser_host_create_messages_.clear(); 271 browser_vars_.clear(); 272 } 273 274 bool ResourceConverterImpl::NeedsFlush() { 275 return !browser_host_create_messages_.empty(); 276 } 277 278 void ResourceConverterImpl::Flush(const base::Callback<void(bool)>& callback) { 279 host_->CreateBrowserResourceHosts( 280 instance_, 281 browser_host_create_messages_, 282 base::Bind(&FlushComplete, callback, browser_vars_)); 283 browser_host_create_messages_.clear(); 284 browser_vars_.clear(); 285 } 286 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); 291 292 ResourceVar* resource = ResourceVar::FromPPVar(var); 293 if (!resource) { 294 NOTREACHED(); 295 return false; 296 } 297 PP_Resource resource_id = resource->GetPPResource(); 298 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. 306 NOTREACHED(); 307 return false; 308 } 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; 314 return false; 315 } 316 317 // Convert to the appropriate type of resource host. 318 if (resource_host->IsFileSystemHost()) { 319 return ResourceHostToDOMFileSystem( 320 static_cast<content::PepperFileSystemHost*>(resource_host), 321 context, 322 result); 323 } else if (resource_host->IsMediaStreamVideoTrackHost()) { 324 return ResourceHostToDOMMediaStreamVideoTrack( 325 static_cast<content::PepperMediaStreamVideoTrackHost*>(resource_host), 326 context, 327 result); 328 } else { 329 LOG(ERROR) << "The type of resource #" << resource_id 330 << " cannot be converted to a JavaScript object."; 331 return false; 332 } 333 } 334 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); 339 } 340 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); 350 return result; 351 } 352 353 } // namespace content 354