OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "extensions/browser/guest_view/web_view/web_view_guest.h" | 5 #include "extensions/browser/guest_view/web_view/web_view_guest.h" |
6 | 6 |
7 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
10 #include "components/browsing_data/storage_partition_http_cache_data_remover.h" | 10 #include "components/browsing_data/storage_partition_http_cache_data_remover.h" |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 return zoom_factor; | 194 return zoom_factor; |
195 } | 195 } |
196 | 196 |
197 using WebViewKey = std::pair<int, int>; | 197 using WebViewKey = std::pair<int, int>; |
198 using WebViewKeyToIDMap = std::map<WebViewKey, int>; | 198 using WebViewKeyToIDMap = std::map<WebViewKey, int>; |
199 static base::LazyInstance<WebViewKeyToIDMap> web_view_key_to_id_map = | 199 static base::LazyInstance<WebViewKeyToIDMap> web_view_key_to_id_map = |
200 LAZY_INSTANCE_INITIALIZER; | 200 LAZY_INSTANCE_INITIALIZER; |
201 | 201 |
202 } // namespace | 202 } // namespace |
203 | 203 |
| 204 WebViewGuest::WebViewGuest(WebContents* owner_web_contents) |
| 205 : GuestView<WebViewGuest>(owner_web_contents), |
| 206 rules_registry_id_(RulesRegistryService::kInvalidRulesRegistryID), |
| 207 find_helper_(this), |
| 208 is_overriding_user_agent_(false), |
| 209 allow_transparency_(false), |
| 210 javascript_dialog_helper_(this), |
| 211 allow_scaling_(false), |
| 212 is_guest_fullscreen_(false), |
| 213 is_embedder_fullscreen_(false), |
| 214 last_fullscreen_permission_was_allowed_by_embedder_(false), |
| 215 pending_zoom_factor_(0.0), |
| 216 weak_ptr_factory_(this) { |
| 217 web_view_guest_delegate_.reset( |
| 218 ExtensionsAPIClient::Get()->CreateWebViewGuestDelegate(this)); |
| 219 } |
| 220 |
| 221 WebViewGuest::~WebViewGuest() {} |
| 222 |
204 // static | 223 // static |
205 void WebViewGuest::CleanUp(content::BrowserContext* browser_context, | 224 void WebViewGuest::CleanUp(content::BrowserContext* browser_context, |
206 int embedder_process_id, | 225 int embedder_process_id, |
207 int view_instance_id) { | 226 int view_instance_id) { |
208 GuestViewBase::CleanUp(browser_context, embedder_process_id, | 227 GuestViewBase::CleanUp(browser_context, embedder_process_id, |
209 view_instance_id); | 228 view_instance_id); |
210 | 229 |
211 // Clean up rules registries for the WebView. | 230 // Clean up rules registries for the WebView. |
212 WebViewKey key(embedder_process_id, view_instance_id); | 231 WebViewKey key(embedder_process_id, view_instance_id); |
213 auto it = web_view_key_to_id_map.Get().find(key); | 232 auto it = web_view_key_to_id_map.Get().find(key); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 return it->second; | 315 return it->second; |
297 | 316 |
298 auto rph = RenderProcessHost::FromID(embedder_process_id); | 317 auto rph = RenderProcessHost::FromID(embedder_process_id); |
299 int rules_registry_id = | 318 int rules_registry_id = |
300 RulesRegistryService::Get(rph->GetBrowserContext())-> | 319 RulesRegistryService::Get(rph->GetBrowserContext())-> |
301 GetNextRulesRegistryID(); | 320 GetNextRulesRegistryID(); |
302 web_view_key_to_id_map.Get()[key] = rules_registry_id; | 321 web_view_key_to_id_map.Get()[key] = rules_registry_id; |
303 return rules_registry_id; | 322 return rules_registry_id; |
304 } | 323 } |
305 | 324 |
306 bool WebViewGuest::CanRunInDetachedState() const { | 325 double WebViewGuest::GetZoom() const { |
307 return true; | 326 double zoom_level = |
| 327 ZoomController::FromWebContents(web_contents())->GetZoomLevel(); |
| 328 return ConvertZoomLevelToZoomFactor(zoom_level); |
308 } | 329 } |
309 | 330 |
310 void WebViewGuest::CreateWebContents( | 331 ZoomController::ZoomMode WebViewGuest::GetZoomMode() { |
311 const base::DictionaryValue& create_params, | 332 return ZoomController::FromWebContents(web_contents())->zoom_mode(); |
312 const WebContentsCreatedCallback& callback) { | 333 } |
313 RenderProcessHost* owner_render_process_host = | 334 |
314 owner_web_contents()->GetRenderProcessHost(); | 335 void WebViewGuest::NavigateGuest(const std::string& src, |
315 std::string storage_partition_id; | 336 bool force_navigation) { |
316 bool persist_storage = false; | 337 if (src.empty()) |
317 ParsePartitionParam(create_params, &storage_partition_id, &persist_storage); | 338 return; |
318 // Validate that the partition id coming from the renderer is valid UTF-8, | 339 |
319 // since we depend on this in other parts of the code, such as FilePath | 340 GURL url = ResolveURL(src); |
320 // creation. If the validation fails, treat it as a bad message and kill the | 341 |
321 // renderer process. | 342 // We wait for all the content scripts to load and then navigate the guest |
322 if (!base::IsStringUTF8(storage_partition_id)) { | 343 // if the navigation is embedder-initiated. For browser-initiated navigations, |
323 content::RecordAction( | 344 // content scripts will be ready. |
324 base::UserMetricsAction("BadMessageTerminate_BPGM")); | 345 if (force_navigation) { |
325 owner_render_process_host->Shutdown(content::RESULT_CODE_KILLED_BAD_MESSAGE, | 346 SignalWhenReady(base::Bind( |
326 false); | 347 &WebViewGuest::LoadURLWithParams, weak_ptr_factory_.GetWeakPtr(), url, |
327 callback.Run(nullptr); | 348 content::Referrer(), ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
| 349 GlobalRequestID(), force_navigation)); |
328 return; | 350 return; |
329 } | 351 } |
330 std::string url_encoded_partition = net::EscapeQueryParamValue( | 352 LoadURLWithParams(url, content::Referrer(), ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
331 storage_partition_id, false); | 353 GlobalRequestID(), force_navigation); |
332 std::string partition_domain = GetOwnerSiteURL().host(); | |
333 GURL guest_site(base::StringPrintf("%s://%s/%s?%s", | |
334 content::kGuestScheme, | |
335 partition_domain.c_str(), | |
336 persist_storage ? "persist" : "", | |
337 url_encoded_partition.c_str())); | |
338 | |
339 // If we already have a webview tag in the same app using the same storage | |
340 // partition, we should use the same SiteInstance so the existing tag and | |
341 // the new tag can script each other. | |
342 auto guest_view_manager = GuestViewManager::FromBrowserContext( | |
343 owner_render_process_host->GetBrowserContext()); | |
344 content::SiteInstance* guest_site_instance = | |
345 guest_view_manager->GetGuestSiteInstance(guest_site); | |
346 if (!guest_site_instance) { | |
347 // Create the SiteInstance in a new BrowsingInstance, which will ensure | |
348 // that webview tags are also not allowed to send messages across | |
349 // different partitions. | |
350 guest_site_instance = content::SiteInstance::CreateForURL( | |
351 owner_render_process_host->GetBrowserContext(), guest_site); | |
352 } | |
353 WebContents::CreateParams params( | |
354 owner_render_process_host->GetBrowserContext(), | |
355 guest_site_instance); | |
356 params.guest_delegate = this; | |
357 callback.Run(WebContents::Create(params)); | |
358 } | 354 } |
359 | 355 |
360 void WebViewGuest::DidAttachToEmbedder() { | 356 void WebViewGuest::ShowContextMenu( |
361 ApplyAttributes(*attach_params()); | 357 int request_id, |
| 358 const WebViewGuestDelegate::MenuItemVector* items) { |
| 359 if (web_view_guest_delegate_) |
| 360 web_view_guest_delegate_->OnShowContextMenu(request_id, items); |
362 } | 361 } |
363 | 362 |
364 void WebViewGuest::DidDropLink(const GURL& url) { | 363 void WebViewGuest::SetName(const std::string& name) { |
365 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | 364 if (name_ == name) |
366 args->SetString(guest_view::kUrl, url.spec()); | 365 return; |
367 DispatchEventToView( | 366 name_ = name; |
368 new GuestViewEvent(webview::kEventDropLink, args.Pass())); | 367 |
| 368 Send(new ExtensionMsg_SetFrameName(routing_id(), name_)); |
369 } | 369 } |
370 | 370 |
371 void WebViewGuest::DidInitialize(const base::DictionaryValue& create_params) { | 371 void WebViewGuest::SetZoom(double zoom_factor) { |
372 script_executor_.reset( | 372 auto zoom_controller = ZoomController::FromWebContents(web_contents()); |
373 new ScriptExecutor(web_contents(), &script_observers_)); | 373 DCHECK(zoom_controller); |
374 | 374 double zoom_level = content::ZoomFactorToZoomLevel(zoom_factor); |
375 notification_registrar_.Add(this, | 375 zoom_controller->SetZoomLevel(zoom_level); |
376 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, | |
377 content::Source<WebContents>(web_contents())); | |
378 | |
379 notification_registrar_.Add(this, | |
380 content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, | |
381 content::Source<WebContents>(web_contents())); | |
382 | |
383 if (web_view_guest_delegate_) | |
384 web_view_guest_delegate_->OnDidInitialize(); | |
385 ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents()); | |
386 web_view_permission_helper_.reset(new WebViewPermissionHelper(this)); | |
387 | |
388 rules_registry_id_ = GetOrGenerateRulesRegistryID( | |
389 owner_web_contents()->GetRenderProcessHost()->GetID(), | |
390 view_instance_id()); | |
391 | |
392 // We must install the mapping from guests to WebViews prior to resuming | |
393 // suspended resource loads so that the WebRequest API will catch resource | |
394 // requests. | |
395 PushWebViewStateToIOThread(); | |
396 | |
397 ApplyAttributes(create_params); | |
398 } | 376 } |
399 | 377 |
400 void WebViewGuest::ClearDataInternal(base::Time remove_since, | 378 void WebViewGuest::SetZoomMode(ZoomController::ZoomMode zoom_mode) { |
401 uint32 removal_mask, | 379 ZoomController::FromWebContents(web_contents())->SetZoomMode(zoom_mode); |
402 const base::Closure& callback) { | |
403 uint32 storage_partition_removal_mask = | |
404 GetStoragePartitionRemovalMask(removal_mask); | |
405 if (!storage_partition_removal_mask) { | |
406 callback.Run(); | |
407 return; | |
408 } | |
409 content::StoragePartition* partition = | |
410 content::BrowserContext::GetStoragePartition( | |
411 web_contents()->GetBrowserContext(), | |
412 web_contents()->GetSiteInstance()); | |
413 partition->ClearData( | |
414 storage_partition_removal_mask, | |
415 content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, GURL(), | |
416 content::StoragePartition::OriginMatcherFunction(), remove_since, | |
417 base::Time::Now(), callback); | |
418 } | 380 } |
419 | 381 |
420 void WebViewGuest::GuestViewDidStopLoading() { | 382 void WebViewGuest::SetAllowScaling(bool allow) { |
421 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | 383 allow_scaling_ = allow; |
422 DispatchEventToView( | |
423 new GuestViewEvent(webview::kEventLoadStop, args.Pass())); | |
424 } | 384 } |
425 | 385 |
426 void WebViewGuest::EmbedderFullscreenToggled(bool entered_fullscreen) { | 386 void WebViewGuest::SetAllowTransparency(bool allow) { |
427 is_embedder_fullscreen_ = entered_fullscreen; | 387 if (allow_transparency_ == allow) |
428 // If the embedder has got out of fullscreen, we get out of fullscreen | 388 return; |
429 // mode as well. | |
430 if (!entered_fullscreen) | |
431 SetFullscreenState(false); | |
432 } | |
433 | 389 |
434 const char* WebViewGuest::GetAPINamespace() const { | 390 allow_transparency_ = allow; |
435 return webview::kAPINamespace; | 391 if (!web_contents()->GetRenderViewHost()->GetView()) |
436 } | 392 return; |
437 | 393 |
438 int WebViewGuest::GetTaskPrefix() const { | |
439 return IDS_EXTENSION_TASK_MANAGER_WEBVIEW_TAG_PREFIX; | |
440 } | |
441 | |
442 void WebViewGuest::GuestDestroyed() { | |
443 RemoveWebViewStateFromIOThread(web_contents()); | |
444 } | |
445 | |
446 void WebViewGuest::GuestReady() { | |
447 // The guest RenderView should always live in an isolated guest process. | |
448 CHECK(web_contents()->GetRenderProcessHost()->IsForGuestsOnly()); | |
449 Send(new ExtensionMsg_SetFrameName(web_contents()->GetRoutingID(), name_)); | |
450 | |
451 // We don't want to accidentally set the opacity of an interstitial page. | |
452 // WebContents::GetRenderWidgetHostView will return the RWHV of an | |
453 // interstitial page if one is showing at this time. We only want opacity | |
454 // to apply to web pages. | |
455 if (allow_transparency_) { | 394 if (allow_transparency_) { |
456 web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor( | 395 web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor( |
457 SK_ColorTRANSPARENT); | 396 SK_ColorTRANSPARENT); |
458 } else { | 397 } else { |
459 web_contents() | 398 web_contents() |
460 ->GetRenderViewHost() | 399 ->GetRenderViewHost() |
461 ->GetView() | 400 ->GetView() |
462 ->SetBackgroundColorToDefault(); | 401 ->SetBackgroundColorToDefault(); |
463 } | 402 } |
464 } | 403 } |
465 | 404 |
466 void WebViewGuest::GuestSizeChangedDueToAutoSize(const gfx::Size& old_size, | 405 bool WebViewGuest::LoadDataWithBaseURL(const std::string& data_url, |
467 const gfx::Size& new_size) { | 406 const std::string& base_url, |
468 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | 407 const std::string& virtual_url, |
469 args->SetInteger(webview::kOldHeight, old_size.height()); | 408 std::string* error) { |
470 args->SetInteger(webview::kOldWidth, old_size.width()); | 409 // Make GURLs from URLs. |
471 args->SetInteger(webview::kNewHeight, new_size.height()); | 410 const GURL data_gurl = GURL(data_url); |
472 args->SetInteger(webview::kNewWidth, new_size.width()); | 411 const GURL base_gurl = GURL(base_url); |
473 DispatchEventToView( | 412 const GURL virtual_gurl = GURL(virtual_url); |
474 new GuestViewEvent(webview::kEventSizeChanged, args.Pass())); | |
475 } | |
476 | 413 |
477 bool WebViewGuest::IsAutoSizeSupported() const { | 414 // Check that the provided URLs are valid. |
| 415 // |data_url| must be a valid data URL. |
| 416 if (!data_gurl.is_valid() || !data_gurl.SchemeIs(url::kDataScheme)) { |
| 417 base::SStringPrintf(error, webview::kAPILoadDataInvalidDataURL, |
| 418 data_url.c_str()); |
| 419 return false; |
| 420 } |
| 421 // |base_url| must be a valid URL. |
| 422 if (!base_gurl.is_valid()) { |
| 423 base::SStringPrintf(error, webview::kAPILoadDataInvalidBaseURL, |
| 424 base_url.c_str()); |
| 425 return false; |
| 426 } |
| 427 // |virtual_url| must be a valid URL. |
| 428 if (!virtual_gurl.is_valid()) { |
| 429 base::SStringPrintf(error, webview::kAPILoadDataInvalidVirtualURL, |
| 430 virtual_url.c_str()); |
| 431 return false; |
| 432 } |
| 433 |
| 434 // Set up the parameters to load |data_url| with the specified |base_url|. |
| 435 content::NavigationController::LoadURLParams load_params(data_gurl); |
| 436 load_params.load_type = content::NavigationController::LOAD_TYPE_DATA; |
| 437 load_params.base_url_for_data_url = base_gurl; |
| 438 load_params.virtual_url_for_data_url = virtual_gurl; |
| 439 load_params.override_user_agent = |
| 440 content::NavigationController::UA_OVERRIDE_INHERIT; |
| 441 |
| 442 // Navigate to the data URL. |
| 443 GuestViewBase::LoadURLWithParams(load_params); |
| 444 |
478 return true; | 445 return true; |
479 } | 446 } |
480 | 447 |
481 void WebViewGuest::GuestZoomChanged(double old_zoom_level, | |
482 double new_zoom_level) { | |
483 // Dispatch the zoomchange event. | |
484 double old_zoom_factor = ConvertZoomLevelToZoomFactor(old_zoom_level); | |
485 double new_zoom_factor = ConvertZoomLevelToZoomFactor(new_zoom_level); | |
486 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
487 args->SetDouble(webview::kOldZoomFactor, old_zoom_factor); | |
488 args->SetDouble(webview::kNewZoomFactor, new_zoom_factor); | |
489 DispatchEventToView( | |
490 new GuestViewEvent(webview::kEventZoomChange, args.Pass())); | |
491 } | |
492 | |
493 void WebViewGuest::WillDestroy() { | |
494 if (!attached() && GetOpener()) | |
495 GetOpener()->pending_new_windows_.erase(this); | |
496 } | |
497 | |
498 bool WebViewGuest::AddMessageToConsole(WebContents* source, | |
499 int32 level, | |
500 const base::string16& message, | |
501 int32 line_no, | |
502 const base::string16& source_id) { | |
503 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
504 // Log levels are from base/logging.h: LogSeverity. | |
505 args->SetInteger(webview::kLevel, level); | |
506 args->SetString(webview::kMessage, message); | |
507 args->SetInteger(webview::kLine, line_no); | |
508 args->SetString(webview::kSourceId, source_id); | |
509 DispatchEventToView( | |
510 new GuestViewEvent(webview::kEventConsoleMessage, args.Pass())); | |
511 return true; | |
512 } | |
513 | |
514 void WebViewGuest::CloseContents(WebContents* source) { | |
515 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
516 DispatchEventToView( | |
517 new GuestViewEvent(webview::kEventClose, args.Pass())); | |
518 } | |
519 | |
520 void WebViewGuest::FindReply(WebContents* source, | |
521 int request_id, | |
522 int number_of_matches, | |
523 const gfx::Rect& selection_rect, | |
524 int active_match_ordinal, | |
525 bool final_update) { | |
526 GuestViewBase::FindReply(source, request_id, number_of_matches, | |
527 selection_rect, active_match_ordinal, final_update); | |
528 find_helper_.FindReply(request_id, number_of_matches, selection_rect, | |
529 active_match_ordinal, final_update); | |
530 } | |
531 | |
532 double WebViewGuest::GetZoom() const { | |
533 double zoom_level = | |
534 ZoomController::FromWebContents(web_contents())->GetZoomLevel(); | |
535 return ConvertZoomLevelToZoomFactor(zoom_level); | |
536 } | |
537 | |
538 ZoomController::ZoomMode WebViewGuest::GetZoomMode() { | |
539 return ZoomController::FromWebContents(web_contents())->zoom_mode(); | |
540 } | |
541 | |
542 bool WebViewGuest::HandleContextMenu( | |
543 const content::ContextMenuParams& params) { | |
544 if (!web_view_guest_delegate_) | |
545 return false; | |
546 return web_view_guest_delegate_->HandleContextMenu(params); | |
547 } | |
548 | |
549 void WebViewGuest::HandleKeyboardEvent( | |
550 WebContents* source, | |
551 const content::NativeWebKeyboardEvent& event) { | |
552 if (HandleKeyboardShortcuts(event)) | |
553 return; | |
554 | |
555 GuestViewBase::HandleKeyboardEvent(source, event); | |
556 } | |
557 | |
558 bool WebViewGuest::PreHandleGestureEvent(WebContents* source, | |
559 const blink::WebGestureEvent& event) { | |
560 return !allow_scaling_ && GuestViewBase::PreHandleGestureEvent(source, event); | |
561 } | |
562 | |
563 void WebViewGuest::LoadProgressChanged(WebContents* source, double progress) { | |
564 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
565 args->SetString(guest_view::kUrl, web_contents()->GetURL().spec()); | |
566 args->SetDouble(webview::kProgress, progress); | |
567 DispatchEventToView( | |
568 new GuestViewEvent(webview::kEventLoadProgress, args.Pass())); | |
569 } | |
570 | |
571 void WebViewGuest::LoadAbort(bool is_top_level, | |
572 const GURL& url, | |
573 int error_code, | |
574 const std::string& error_type) { | |
575 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
576 args->SetBoolean(guest_view::kIsTopLevel, is_top_level); | |
577 args->SetString(guest_view::kUrl, url.possibly_invalid_spec()); | |
578 args->SetInteger(guest_view::kCode, error_code); | |
579 args->SetString(guest_view::kReason, error_type); | |
580 DispatchEventToView( | |
581 new GuestViewEvent(webview::kEventLoadAbort, args.Pass())); | |
582 } | |
583 | |
584 void WebViewGuest::SetContextMenuPosition(const gfx::Point& position) { | |
585 if (web_view_guest_delegate_) | |
586 web_view_guest_delegate_->SetContextMenuPosition(position); | |
587 } | |
588 | |
589 void WebViewGuest::CreateNewGuestWebViewWindow( | |
590 const content::OpenURLParams& params) { | |
591 GuestViewManager* guest_manager = | |
592 GuestViewManager::FromBrowserContext(browser_context()); | |
593 // Set the attach params to use the same partition as the opener. | |
594 // We pull the partition information from the site's URL, which is of the | |
595 // form guest://site/{persist}?{partition_name}. | |
596 const GURL& site_url = web_contents()->GetSiteInstance()->GetSiteURL(); | |
597 const std::string storage_partition_id = | |
598 GetStoragePartitionIdFromSiteURL(site_url); | |
599 base::DictionaryValue create_params; | |
600 create_params.SetString(webview::kStoragePartitionId, storage_partition_id); | |
601 | |
602 guest_manager->CreateGuest(WebViewGuest::Type, | |
603 embedder_web_contents(), | |
604 create_params, | |
605 base::Bind(&WebViewGuest::NewGuestWebViewCallback, | |
606 weak_ptr_factory_.GetWeakPtr(), | |
607 params)); | |
608 } | |
609 | |
610 void WebViewGuest::NewGuestWebViewCallback(const content::OpenURLParams& params, | |
611 WebContents* guest_web_contents) { | |
612 WebViewGuest* new_guest = WebViewGuest::FromWebContents(guest_web_contents); | |
613 new_guest->SetOpener(this); | |
614 | |
615 // Take ownership of |new_guest|. | |
616 pending_new_windows_.insert( | |
617 std::make_pair(new_guest, NewWindowInfo(params.url, std::string()))); | |
618 | |
619 // Request permission to show the new window. | |
620 RequestNewWindowPermission(params.disposition, | |
621 gfx::Rect(), | |
622 params.user_gesture, | |
623 new_guest->web_contents()); | |
624 } | |
625 | |
626 // TODO(fsamuel): Find a reliable way to test the 'responsive' and | |
627 // 'unresponsive' events. | |
628 void WebViewGuest::RendererResponsive(WebContents* source) { | |
629 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
630 args->SetInteger(webview::kProcessId, | |
631 web_contents()->GetRenderProcessHost()->GetID()); | |
632 DispatchEventToView( | |
633 new GuestViewEvent(webview::kEventResponsive, args.Pass())); | |
634 } | |
635 | |
636 void WebViewGuest::RendererUnresponsive(WebContents* source) { | |
637 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
638 args->SetInteger(webview::kProcessId, | |
639 web_contents()->GetRenderProcessHost()->GetID()); | |
640 DispatchEventToView( | |
641 new GuestViewEvent(webview::kEventUnresponsive, args.Pass())); | |
642 } | |
643 | |
644 void WebViewGuest::Observe(int type, | |
645 const content::NotificationSource& source, | |
646 const content::NotificationDetails& details) { | |
647 switch (type) { | |
648 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: { | |
649 DCHECK_EQ(content::Source<WebContents>(source).ptr(), web_contents()); | |
650 if (content::Source<WebContents>(source).ptr() == web_contents()) | |
651 LoadHandlerCalled(); | |
652 break; | |
653 } | |
654 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: { | |
655 DCHECK_EQ(content::Source<WebContents>(source).ptr(), web_contents()); | |
656 content::ResourceRedirectDetails* resource_redirect_details = | |
657 content::Details<content::ResourceRedirectDetails>(details).ptr(); | |
658 bool is_top_level = resource_redirect_details->resource_type == | |
659 content::RESOURCE_TYPE_MAIN_FRAME; | |
660 LoadRedirect(resource_redirect_details->url, | |
661 resource_redirect_details->new_url, | |
662 is_top_level); | |
663 break; | |
664 } | |
665 default: | |
666 NOTREACHED() << "Unexpected notification sent."; | |
667 break; | |
668 } | |
669 } | |
670 | |
671 void WebViewGuest::StartFindInternal( | 448 void WebViewGuest::StartFindInternal( |
672 const base::string16& search_text, | 449 const base::string16& search_text, |
673 const blink::WebFindOptions& options, | 450 const blink::WebFindOptions& options, |
674 scoped_refptr<WebViewInternalFindFunction> find_function) { | 451 scoped_refptr<WebViewInternalFindFunction> find_function) { |
675 find_helper_.Find(web_contents(), search_text, options, find_function); | 452 find_helper_.Find(web_contents(), search_text, options, find_function); |
676 } | 453 } |
677 | 454 |
678 void WebViewGuest::StopFindingInternal(content::StopFindAction action) { | 455 void WebViewGuest::StopFindingInternal(content::StopFindAction action) { |
679 find_helper_.CancelAllFindSessions(); | 456 find_helper_.CancelAllFindSessions(); |
680 web_contents()->StopFinding(action); | 457 web_contents()->StopFinding(action); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
749 partition, remove_since, base::Time::Now()) | 526 partition, remove_since, base::Time::Now()) |
750 ->Remove(cache_removal_done_callback); | 527 ->Remove(cache_removal_done_callback); |
751 | 528 |
752 return true; | 529 return true; |
753 } | 530 } |
754 | 531 |
755 ClearDataInternal(remove_since, removal_mask, callback); | 532 ClearDataInternal(remove_since, removal_mask, callback); |
756 return true; | 533 return true; |
757 } | 534 } |
758 | 535 |
759 WebViewGuest::WebViewGuest(WebContents* owner_web_contents) | 536 void WebViewGuest::ClearDataInternal(base::Time remove_since, |
760 : GuestView<WebViewGuest>(owner_web_contents), | 537 uint32 removal_mask, |
761 rules_registry_id_(RulesRegistryService::kInvalidRulesRegistryID), | 538 const base::Closure& callback) { |
762 find_helper_(this), | 539 uint32 storage_partition_removal_mask = |
763 is_overriding_user_agent_(false), | 540 GetStoragePartitionRemovalMask(removal_mask); |
764 allow_transparency_(false), | 541 if (!storage_partition_removal_mask) { |
765 javascript_dialog_helper_(this), | 542 callback.Run(); |
766 allow_scaling_(false), | 543 return; |
767 is_guest_fullscreen_(false), | 544 } |
768 is_embedder_fullscreen_(false), | 545 content::StoragePartition* partition = |
769 last_fullscreen_permission_was_allowed_by_embedder_(false), | 546 content::BrowserContext::GetStoragePartition( |
770 pending_zoom_factor_(0.0), | 547 web_contents()->GetBrowserContext(), |
771 weak_ptr_factory_(this) { | 548 web_contents()->GetSiteInstance()); |
772 web_view_guest_delegate_.reset( | 549 partition->ClearData( |
773 ExtensionsAPIClient::Get()->CreateWebViewGuestDelegate(this)); | 550 storage_partition_removal_mask, |
774 } | 551 content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, GURL(), |
775 | 552 content::StoragePartition::OriginMatcherFunction(), remove_since, |
776 WebViewGuest::~WebViewGuest() { | 553 base::Time::Now(), callback); |
777 } | 554 } |
778 | 555 |
779 void WebViewGuest::DidCommitProvisionalLoadForFrame( | 556 void WebViewGuest::OnWebViewNewWindowResponse(int new_window_instance_id, |
780 content::RenderFrameHost* render_frame_host, | 557 bool allow, |
781 const GURL& url, | 558 const std::string& user_input) { |
782 ui::PageTransition transition_type) { | 559 auto guest = |
783 if (!render_frame_host->GetParent()) { | 560 WebViewGuest::From(owner_web_contents()->GetRenderProcessHost()->GetID(), |
784 src_ = url; | 561 new_window_instance_id); |
785 // Handle a pending zoom if one exists. | 562 if (!guest) |
786 if (pending_zoom_factor_) { | 563 return; |
787 SetZoom(pending_zoom_factor_); | 564 |
788 pending_zoom_factor_ = 0.0; | 565 if (!allow) |
789 } | 566 guest->Destroy(); |
790 } | 567 } |
| 568 |
| 569 void WebViewGuest::OnFullscreenPermissionDecided( |
| 570 bool allowed, |
| 571 const std::string& user_input) { |
| 572 last_fullscreen_permission_was_allowed_by_embedder_ = allowed; |
| 573 SetFullscreenState(allowed); |
| 574 } |
| 575 |
| 576 bool WebViewGuest::GuestMadeEmbedderFullscreen() const { |
| 577 return last_fullscreen_permission_was_allowed_by_embedder_ && |
| 578 is_embedder_fullscreen_; |
| 579 } |
| 580 |
| 581 void WebViewGuest::SetFullscreenState(bool is_fullscreen) { |
| 582 if (is_fullscreen == is_guest_fullscreen_) |
| 583 return; |
| 584 |
| 585 bool was_fullscreen = is_guest_fullscreen_; |
| 586 is_guest_fullscreen_ = is_fullscreen; |
| 587 // If the embedder entered fullscreen because of us, it should exit fullscreen |
| 588 // when we exit fullscreen. |
| 589 if (was_fullscreen && GuestMadeEmbedderFullscreen()) { |
| 590 // Dispatch a message so we can call document.webkitCancelFullscreen() |
| 591 // on the embedder. |
| 592 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 593 DispatchEventToView( |
| 594 new GuestViewEvent(webview::kEventExitFullscreen, args.Pass())); |
| 595 } |
| 596 // Since we changed fullscreen state, sending a Resize message ensures that |
| 597 // renderer/ sees the change. |
| 598 web_contents()->GetRenderViewHost()->WasResized(); |
| 599 } |
| 600 |
| 601 bool WebViewGuest::CanRunInDetachedState() const { |
| 602 return true; |
| 603 } |
| 604 |
| 605 void WebViewGuest::CreateWebContents( |
| 606 const base::DictionaryValue& create_params, |
| 607 const WebContentsCreatedCallback& callback) { |
| 608 RenderProcessHost* owner_render_process_host = |
| 609 owner_web_contents()->GetRenderProcessHost(); |
| 610 std::string storage_partition_id; |
| 611 bool persist_storage = false; |
| 612 ParsePartitionParam(create_params, &storage_partition_id, &persist_storage); |
| 613 // Validate that the partition id coming from the renderer is valid UTF-8, |
| 614 // since we depend on this in other parts of the code, such as FilePath |
| 615 // creation. If the validation fails, treat it as a bad message and kill the |
| 616 // renderer process. |
| 617 if (!base::IsStringUTF8(storage_partition_id)) { |
| 618 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_BPGM")); |
| 619 owner_render_process_host->Shutdown(content::RESULT_CODE_KILLED_BAD_MESSAGE, |
| 620 false); |
| 621 callback.Run(nullptr); |
| 622 return; |
| 623 } |
| 624 std::string url_encoded_partition = |
| 625 net::EscapeQueryParamValue(storage_partition_id, false); |
| 626 std::string partition_domain = GetOwnerSiteURL().host(); |
| 627 GURL guest_site(base::StringPrintf( |
| 628 "%s://%s/%s?%s", content::kGuestScheme, partition_domain.c_str(), |
| 629 persist_storage ? "persist" : "", url_encoded_partition.c_str())); |
| 630 |
| 631 // If we already have a webview tag in the same app using the same storage |
| 632 // partition, we should use the same SiteInstance so the existing tag and |
| 633 // the new tag can script each other. |
| 634 auto guest_view_manager = GuestViewManager::FromBrowserContext( |
| 635 owner_render_process_host->GetBrowserContext()); |
| 636 content::SiteInstance* guest_site_instance = |
| 637 guest_view_manager->GetGuestSiteInstance(guest_site); |
| 638 if (!guest_site_instance) { |
| 639 // Create the SiteInstance in a new BrowsingInstance, which will ensure |
| 640 // that webview tags are also not allowed to send messages across |
| 641 // different partitions. |
| 642 guest_site_instance = content::SiteInstance::CreateForURL( |
| 643 owner_render_process_host->GetBrowserContext(), guest_site); |
| 644 } |
| 645 WebContents::CreateParams params( |
| 646 owner_render_process_host->GetBrowserContext(), guest_site_instance); |
| 647 params.guest_delegate = this; |
| 648 callback.Run(WebContents::Create(params)); |
| 649 } |
| 650 |
| 651 void WebViewGuest::DidAttachToEmbedder() { |
| 652 ApplyAttributes(*attach_params()); |
| 653 } |
| 654 |
| 655 void WebViewGuest::DidDropLink(const GURL& url) { |
791 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | 656 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
792 args->SetString(guest_view::kUrl, url.spec()); | 657 args->SetString(guest_view::kUrl, url.spec()); |
793 args->SetBoolean(guest_view::kIsTopLevel, !render_frame_host->GetParent()); | 658 DispatchEventToView(new GuestViewEvent(webview::kEventDropLink, args.Pass())); |
794 args->SetString(webview::kInternalBaseURLForDataURL, | 659 } |
795 web_contents() | 660 |
796 ->GetController() | 661 void WebViewGuest::DidInitialize(const base::DictionaryValue& create_params) { |
797 .GetLastCommittedEntry() | 662 script_executor_.reset( |
798 ->GetBaseURLForDataURL() | 663 new ScriptExecutor(web_contents(), &script_observers_)); |
799 .spec()); | 664 |
800 args->SetInteger(webview::kInternalCurrentEntryIndex, | 665 notification_registrar_.Add(this, |
801 web_contents()->GetController().GetCurrentEntryIndex()); | 666 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, |
802 args->SetInteger(webview::kInternalEntryCount, | 667 content::Source<WebContents>(web_contents())); |
803 web_contents()->GetController().GetEntryCount()); | 668 |
804 args->SetInteger(webview::kInternalProcessId, | 669 notification_registrar_.Add(this, |
805 web_contents()->GetRenderProcessHost()->GetID()); | 670 content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, |
| 671 content::Source<WebContents>(web_contents())); |
| 672 |
| 673 if (web_view_guest_delegate_) |
| 674 web_view_guest_delegate_->OnDidInitialize(); |
| 675 ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents()); |
| 676 web_view_permission_helper_.reset(new WebViewPermissionHelper(this)); |
| 677 |
| 678 rules_registry_id_ = GetOrGenerateRulesRegistryID( |
| 679 owner_web_contents()->GetRenderProcessHost()->GetID(), |
| 680 view_instance_id()); |
| 681 |
| 682 // We must install the mapping from guests to WebViews prior to resuming |
| 683 // suspended resource loads so that the WebRequest API will catch resource |
| 684 // requests. |
| 685 PushWebViewStateToIOThread(); |
| 686 |
| 687 ApplyAttributes(create_params); |
| 688 } |
| 689 |
| 690 void WebViewGuest::EmbedderFullscreenToggled(bool entered_fullscreen) { |
| 691 is_embedder_fullscreen_ = entered_fullscreen; |
| 692 // If the embedder has got out of fullscreen, we get out of fullscreen |
| 693 // mode as well. |
| 694 if (!entered_fullscreen) |
| 695 SetFullscreenState(false); |
| 696 } |
| 697 |
| 698 void WebViewGuest::FindReply(WebContents* source, |
| 699 int request_id, |
| 700 int number_of_matches, |
| 701 const gfx::Rect& selection_rect, |
| 702 int active_match_ordinal, |
| 703 bool final_update) { |
| 704 GuestViewBase::FindReply(source, request_id, number_of_matches, |
| 705 selection_rect, active_match_ordinal, final_update); |
| 706 find_helper_.FindReply(request_id, number_of_matches, selection_rect, |
| 707 active_match_ordinal, final_update); |
| 708 } |
| 709 |
| 710 const char* WebViewGuest::GetAPINamespace() const { |
| 711 return webview::kAPINamespace; |
| 712 } |
| 713 |
| 714 int WebViewGuest::GetTaskPrefix() const { |
| 715 return IDS_EXTENSION_TASK_MANAGER_WEBVIEW_TAG_PREFIX; |
| 716 } |
| 717 |
| 718 void WebViewGuest::GuestDestroyed() { |
| 719 RemoveWebViewStateFromIOThread(web_contents()); |
| 720 } |
| 721 |
| 722 void WebViewGuest::GuestReady() { |
| 723 // The guest RenderView should always live in an isolated guest process. |
| 724 CHECK(web_contents()->GetRenderProcessHost()->IsForGuestsOnly()); |
| 725 Send(new ExtensionMsg_SetFrameName(web_contents()->GetRoutingID(), name_)); |
| 726 |
| 727 // We don't want to accidentally set the opacity of an interstitial page. |
| 728 // WebContents::GetRenderWidgetHostView will return the RWHV of an |
| 729 // interstitial page if one is showing at this time. We only want opacity |
| 730 // to apply to web pages. |
| 731 if (allow_transparency_) { |
| 732 web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor( |
| 733 SK_ColorTRANSPARENT); |
| 734 } else { |
| 735 web_contents() |
| 736 ->GetRenderViewHost() |
| 737 ->GetView() |
| 738 ->SetBackgroundColorToDefault(); |
| 739 } |
| 740 } |
| 741 |
| 742 void WebViewGuest::GuestSizeChangedDueToAutoSize(const gfx::Size& old_size, |
| 743 const gfx::Size& new_size) { |
| 744 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 745 args->SetInteger(webview::kOldHeight, old_size.height()); |
| 746 args->SetInteger(webview::kOldWidth, old_size.width()); |
| 747 args->SetInteger(webview::kNewHeight, new_size.height()); |
| 748 args->SetInteger(webview::kNewWidth, new_size.width()); |
806 DispatchEventToView( | 749 DispatchEventToView( |
807 new GuestViewEvent(webview::kEventLoadCommit, args.Pass())); | 750 new GuestViewEvent(webview::kEventSizeChanged, args.Pass())); |
808 | 751 } |
809 find_helper_.CancelAllFindSessions(); | 752 |
810 } | 753 void WebViewGuest::GuestViewDidStopLoading() { |
811 | 754 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
812 void WebViewGuest::DidFailProvisionalLoad( | 755 DispatchEventToView(new GuestViewEvent(webview::kEventLoadStop, args.Pass())); |
813 content::RenderFrameHost* render_frame_host, | 756 } |
814 const GURL& validated_url, | 757 |
815 int error_code, | 758 void WebViewGuest::GuestZoomChanged(double old_zoom_level, |
816 const base::string16& error_description, | 759 double new_zoom_level) { |
817 bool was_ignored_by_handler) { | 760 // Dispatch the zoomchange event. |
818 // Suppress loadabort for "mailto" URLs. | 761 double old_zoom_factor = ConvertZoomLevelToZoomFactor(old_zoom_level); |
819 if (validated_url.SchemeIs(url::kMailToScheme)) | 762 double new_zoom_factor = ConvertZoomLevelToZoomFactor(new_zoom_level); |
820 return; | 763 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
821 | 764 args->SetDouble(webview::kOldZoomFactor, old_zoom_factor); |
822 LoadAbort(!render_frame_host->GetParent(), validated_url, error_code, | 765 args->SetDouble(webview::kNewZoomFactor, new_zoom_factor); |
823 net::ErrorToShortString(error_code)); | |
824 } | |
825 | |
826 void WebViewGuest::DidStartProvisionalLoadForFrame( | |
827 content::RenderFrameHost* render_frame_host, | |
828 const GURL& validated_url, | |
829 bool is_error_page, | |
830 bool is_iframe_srcdoc) { | |
831 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
832 args->SetString(guest_view::kUrl, validated_url.spec()); | |
833 args->SetBoolean(guest_view::kIsTopLevel, !render_frame_host->GetParent()); | |
834 DispatchEventToView( | 766 DispatchEventToView( |
835 new GuestViewEvent(webview::kEventLoadStart, args.Pass())); | 767 new GuestViewEvent(webview::kEventZoomChange, args.Pass())); |
836 } | 768 } |
837 | 769 |
838 void WebViewGuest::RenderProcessGone(base::TerminationStatus status) { | 770 bool WebViewGuest::IsAutoSizeSupported() const { |
839 // Cancel all find sessions in progress. | 771 return true; |
840 find_helper_.CancelAllFindSessions(); | 772 } |
841 | 773 |
842 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | 774 void WebViewGuest::SetContextMenuPosition(const gfx::Point& position) { |
843 args->SetInteger(webview::kProcessId, | 775 if (web_view_guest_delegate_) |
844 web_contents()->GetRenderProcessHost()->GetID()); | 776 web_view_guest_delegate_->SetContextMenuPosition(position); |
845 args->SetString(webview::kReason, TerminationStatusToString(status)); | |
846 DispatchEventToView( | |
847 new GuestViewEvent(webview::kEventExit, args.Pass())); | |
848 } | |
849 | |
850 void WebViewGuest::UserAgentOverrideSet(const std::string& user_agent) { | |
851 content::NavigationController& controller = web_contents()->GetController(); | |
852 content::NavigationEntry* entry = controller.GetVisibleEntry(); | |
853 if (!entry) | |
854 return; | |
855 entry->SetIsOverridingUserAgent(!user_agent.empty()); | |
856 web_contents()->GetController().Reload(false); | |
857 } | |
858 | |
859 void WebViewGuest::FrameNameChanged(RenderFrameHost* render_frame_host, | |
860 const std::string& name) { | |
861 if (render_frame_host->GetParent()) | |
862 return; | |
863 | |
864 if (name_ == name) | |
865 return; | |
866 | |
867 ReportFrameNameChange(name); | |
868 } | |
869 | |
870 void WebViewGuest::ReportFrameNameChange(const std::string& name) { | |
871 name_ = name; | |
872 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
873 args->SetString(webview::kName, name); | |
874 DispatchEventToView( | |
875 new GuestViewEvent(webview::kEventFrameNameChanged, args.Pass())); | |
876 } | |
877 | |
878 void WebViewGuest::LoadHandlerCalled() { | |
879 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
880 DispatchEventToView( | |
881 new GuestViewEvent(webview::kEventContentLoad, args.Pass())); | |
882 } | |
883 | |
884 void WebViewGuest::LoadRedirect(const GURL& old_url, | |
885 const GURL& new_url, | |
886 bool is_top_level) { | |
887 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
888 args->SetBoolean(guest_view::kIsTopLevel, is_top_level); | |
889 args->SetString(webview::kNewURL, new_url.spec()); | |
890 args->SetString(webview::kOldURL, old_url.spec()); | |
891 DispatchEventToView( | |
892 new GuestViewEvent(webview::kEventLoadRedirect, args.Pass())); | |
893 } | |
894 | |
895 void WebViewGuest::PushWebViewStateToIOThread() { | |
896 const GURL& site_url = web_contents()->GetSiteInstance()->GetSiteURL(); | |
897 std::string partition_domain; | |
898 std::string partition_id; | |
899 bool in_memory; | |
900 if (!GetGuestPartitionConfigForSite( | |
901 site_url, &partition_domain, &partition_id, &in_memory)) { | |
902 NOTREACHED(); | |
903 return; | |
904 } | |
905 | |
906 WebViewRendererState::WebViewInfo web_view_info; | |
907 web_view_info.embedder_process_id = | |
908 owner_web_contents()->GetRenderProcessHost()->GetID(); | |
909 web_view_info.instance_id = view_instance_id(); | |
910 web_view_info.partition_id = partition_id; | |
911 web_view_info.owner_host = owner_host(); | |
912 web_view_info.rules_registry_id = rules_registry_id_; | |
913 | |
914 // Get content scripts IDs added by the guest. | |
915 WebViewContentScriptManager* manager = | |
916 WebViewContentScriptManager::Get(browser_context()); | |
917 DCHECK(manager); | |
918 web_view_info.content_script_ids = manager->GetContentScriptIDSet( | |
919 web_view_info.embedder_process_id, web_view_info.instance_id); | |
920 | |
921 content::BrowserThread::PostTask( | |
922 content::BrowserThread::IO, | |
923 FROM_HERE, | |
924 base::Bind(&WebViewRendererState::AddGuest, | |
925 base::Unretained(WebViewRendererState::GetInstance()), | |
926 web_contents()->GetRenderProcessHost()->GetID(), | |
927 web_contents()->GetRoutingID(), | |
928 web_view_info)); | |
929 } | |
930 | |
931 // static | |
932 void WebViewGuest::RemoveWebViewStateFromIOThread( | |
933 WebContents* web_contents) { | |
934 content::BrowserThread::PostTask( | |
935 content::BrowserThread::IO, FROM_HERE, | |
936 base::Bind( | |
937 &WebViewRendererState::RemoveGuest, | |
938 base::Unretained(WebViewRendererState::GetInstance()), | |
939 web_contents->GetRenderProcessHost()->GetID(), | |
940 web_contents->GetRoutingID())); | |
941 } | |
942 | |
943 void WebViewGuest::RequestMediaAccessPermission( | |
944 WebContents* source, | |
945 const content::MediaStreamRequest& request, | |
946 const content::MediaResponseCallback& callback) { | |
947 web_view_permission_helper_->RequestMediaAccessPermission(source, | |
948 request, | |
949 callback); | |
950 } | |
951 | |
952 bool WebViewGuest::CheckMediaAccessPermission(WebContents* source, | |
953 const GURL& security_origin, | |
954 content::MediaStreamType type) { | |
955 return web_view_permission_helper_->CheckMediaAccessPermission( | |
956 source, security_origin, type); | |
957 } | |
958 | |
959 void WebViewGuest::CanDownload( | |
960 const GURL& url, | |
961 const std::string& request_method, | |
962 const base::Callback<void(bool)>& callback) { | |
963 web_view_permission_helper_->CanDownload(url, request_method, callback); | |
964 } | |
965 | |
966 void WebViewGuest::RequestPointerLockPermission( | |
967 bool user_gesture, | |
968 bool last_unlocked_by_target, | |
969 const base::Callback<void(bool)>& callback) { | |
970 web_view_permission_helper_->RequestPointerLockPermission( | |
971 user_gesture, | |
972 last_unlocked_by_target, | |
973 callback); | |
974 } | 777 } |
975 | 778 |
976 void WebViewGuest::SignalWhenReady(const base::Closure& callback) { | 779 void WebViewGuest::SignalWhenReady(const base::Closure& callback) { |
977 auto manager = WebViewContentScriptManager::Get(browser_context()); | 780 auto manager = WebViewContentScriptManager::Get(browser_context()); |
978 manager->SignalOnScriptsLoaded(callback); | 781 manager->SignalOnScriptsLoaded(callback); |
979 } | 782 } |
980 | 783 |
981 bool WebViewGuest::ShouldHandleFindRequestsForEmbedder() const { | 784 bool WebViewGuest::ShouldHandleFindRequestsForEmbedder() const { |
982 if (web_view_guest_delegate_) | 785 if (web_view_guest_delegate_) |
983 return web_view_guest_delegate_->ShouldHandleFindRequestsForEmbedder(); | 786 return web_view_guest_delegate_->ShouldHandleFindRequestsForEmbedder(); |
984 return false; | 787 return false; |
985 } | 788 } |
986 | 789 |
987 void WebViewGuest::WillAttachToEmbedder() { | 790 void WebViewGuest::WillAttachToEmbedder() { |
988 rules_registry_id_ = GetOrGenerateRulesRegistryID( | 791 rules_registry_id_ = GetOrGenerateRulesRegistryID( |
989 owner_web_contents()->GetRenderProcessHost()->GetID(), | 792 owner_web_contents()->GetRenderProcessHost()->GetID(), |
990 view_instance_id()); | 793 view_instance_id()); |
991 | 794 |
992 // We must install the mapping from guests to WebViews prior to resuming | 795 // We must install the mapping from guests to WebViews prior to resuming |
993 // suspended resource loads so that the WebRequest API will catch resource | 796 // suspended resource loads so that the WebRequest API will catch resource |
994 // requests. | 797 // requests. |
995 PushWebViewStateToIOThread(); | 798 PushWebViewStateToIOThread(); |
996 } | 799 } |
997 | 800 |
| 801 void WebViewGuest::WillDestroy() { |
| 802 if (!attached() && GetOpener()) |
| 803 GetOpener()->pending_new_windows_.erase(this); |
| 804 } |
| 805 |
| 806 void WebViewGuest::Observe(int type, |
| 807 const content::NotificationSource& source, |
| 808 const content::NotificationDetails& details) { |
| 809 switch (type) { |
| 810 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: { |
| 811 DCHECK_EQ(content::Source<WebContents>(source).ptr(), web_contents()); |
| 812 if (content::Source<WebContents>(source).ptr() == web_contents()) |
| 813 LoadHandlerCalled(); |
| 814 break; |
| 815 } |
| 816 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: { |
| 817 DCHECK_EQ(content::Source<WebContents>(source).ptr(), web_contents()); |
| 818 content::ResourceRedirectDetails* resource_redirect_details = |
| 819 content::Details<content::ResourceRedirectDetails>(details).ptr(); |
| 820 bool is_top_level = resource_redirect_details->resource_type == |
| 821 content::RESOURCE_TYPE_MAIN_FRAME; |
| 822 LoadRedirect(resource_redirect_details->url, |
| 823 resource_redirect_details->new_url, is_top_level); |
| 824 break; |
| 825 } |
| 826 default: |
| 827 NOTREACHED() << "Unexpected notification sent."; |
| 828 break; |
| 829 } |
| 830 } |
| 831 |
| 832 bool WebViewGuest::AddMessageToConsole(WebContents* source, |
| 833 int32 level, |
| 834 const base::string16& message, |
| 835 int32 line_no, |
| 836 const base::string16& source_id) { |
| 837 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 838 // Log levels are from base/logging.h: LogSeverity. |
| 839 args->SetInteger(webview::kLevel, level); |
| 840 args->SetString(webview::kMessage, message); |
| 841 args->SetInteger(webview::kLine, line_no); |
| 842 args->SetString(webview::kSourceId, source_id); |
| 843 DispatchEventToView( |
| 844 new GuestViewEvent(webview::kEventConsoleMessage, args.Pass())); |
| 845 return true; |
| 846 } |
| 847 |
| 848 void WebViewGuest::CloseContents(WebContents* source) { |
| 849 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 850 DispatchEventToView(new GuestViewEvent(webview::kEventClose, args.Pass())); |
| 851 } |
| 852 |
| 853 bool WebViewGuest::HandleContextMenu(const content::ContextMenuParams& params) { |
| 854 if (!web_view_guest_delegate_) |
| 855 return false; |
| 856 return web_view_guest_delegate_->HandleContextMenu(params); |
| 857 } |
| 858 |
| 859 void WebViewGuest::HandleKeyboardEvent( |
| 860 WebContents* source, |
| 861 const content::NativeWebKeyboardEvent& event) { |
| 862 if (HandleKeyboardShortcuts(event)) |
| 863 return; |
| 864 |
| 865 GuestViewBase::HandleKeyboardEvent(source, event); |
| 866 } |
| 867 |
| 868 void WebViewGuest::LoadProgressChanged(WebContents* source, double progress) { |
| 869 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 870 args->SetString(guest_view::kUrl, web_contents()->GetURL().spec()); |
| 871 args->SetDouble(webview::kProgress, progress); |
| 872 DispatchEventToView( |
| 873 new GuestViewEvent(webview::kEventLoadProgress, args.Pass())); |
| 874 } |
| 875 |
| 876 bool WebViewGuest::PreHandleGestureEvent(WebContents* source, |
| 877 const blink::WebGestureEvent& event) { |
| 878 return !allow_scaling_ && GuestViewBase::PreHandleGestureEvent(source, event); |
| 879 } |
| 880 |
| 881 // TODO(fsamuel): Find a reliable way to test the 'responsive' and |
| 882 // 'unresponsive' events. |
| 883 void WebViewGuest::RendererResponsive(WebContents* source) { |
| 884 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 885 args->SetInteger(webview::kProcessId, |
| 886 web_contents()->GetRenderProcessHost()->GetID()); |
| 887 DispatchEventToView( |
| 888 new GuestViewEvent(webview::kEventResponsive, args.Pass())); |
| 889 } |
| 890 |
| 891 void WebViewGuest::RendererUnresponsive(WebContents* source) { |
| 892 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 893 args->SetInteger(webview::kProcessId, |
| 894 web_contents()->GetRenderProcessHost()->GetID()); |
| 895 DispatchEventToView( |
| 896 new GuestViewEvent(webview::kEventUnresponsive, args.Pass())); |
| 897 } |
| 898 |
| 899 void WebViewGuest::RequestMediaAccessPermission( |
| 900 WebContents* source, |
| 901 const content::MediaStreamRequest& request, |
| 902 const content::MediaResponseCallback& callback) { |
| 903 web_view_permission_helper_->RequestMediaAccessPermission(source, request, |
| 904 callback); |
| 905 } |
| 906 |
| 907 void WebViewGuest::RequestPointerLockPermission( |
| 908 bool user_gesture, |
| 909 bool last_unlocked_by_target, |
| 910 const base::Callback<void(bool)>& callback) { |
| 911 web_view_permission_helper_->RequestPointerLockPermission( |
| 912 user_gesture, last_unlocked_by_target, callback); |
| 913 } |
| 914 |
| 915 bool WebViewGuest::CheckMediaAccessPermission(WebContents* source, |
| 916 const GURL& security_origin, |
| 917 content::MediaStreamType type) { |
| 918 return web_view_permission_helper_->CheckMediaAccessPermission( |
| 919 source, security_origin, type); |
| 920 } |
| 921 |
| 922 void WebViewGuest::CanDownload(const GURL& url, |
| 923 const std::string& request_method, |
| 924 const base::Callback<void(bool)>& callback) { |
| 925 web_view_permission_helper_->CanDownload(url, request_method, callback); |
| 926 } |
| 927 |
998 content::JavaScriptDialogManager* WebViewGuest::GetJavaScriptDialogManager( | 928 content::JavaScriptDialogManager* WebViewGuest::GetJavaScriptDialogManager( |
999 WebContents* source) { | 929 WebContents* source) { |
1000 return &javascript_dialog_helper_; | 930 return &javascript_dialog_helper_; |
1001 } | 931 } |
1002 | 932 |
1003 void WebViewGuest::NavigateGuest(const std::string& src, | |
1004 bool force_navigation) { | |
1005 if (src.empty()) | |
1006 return; | |
1007 | |
1008 GURL url = ResolveURL(src); | |
1009 | |
1010 // We wait for all the content scripts to load and then navigate the guest | |
1011 // if the navigation is embedder-initiated. For browser-initiated navigations, | |
1012 // content scripts will be ready. | |
1013 if (force_navigation) { | |
1014 SignalWhenReady(base::Bind( | |
1015 &WebViewGuest::LoadURLWithParams, weak_ptr_factory_.GetWeakPtr(), url, | |
1016 content::Referrer(), ui::PAGE_TRANSITION_AUTO_TOPLEVEL, | |
1017 GlobalRequestID(), force_navigation)); | |
1018 return; | |
1019 } | |
1020 LoadURLWithParams(url, content::Referrer(), ui::PAGE_TRANSITION_AUTO_TOPLEVEL, | |
1021 GlobalRequestID(), force_navigation); | |
1022 } | |
1023 | |
1024 bool WebViewGuest::HandleKeyboardShortcuts( | |
1025 const content::NativeWebKeyboardEvent& event) { | |
1026 // <webview> outside of Chrome Apps do not handle keyboard shortcuts. | |
1027 if (!GuestViewManager::FromBrowserContext(browser_context())-> | |
1028 IsOwnedByExtension(this)) { | |
1029 return false; | |
1030 } | |
1031 | |
1032 if (event.type != blink::WebInputEvent::RawKeyDown) | |
1033 return false; | |
1034 | |
1035 // If the user hits the escape key without any modifiers then unlock the | |
1036 // mouse if necessary. | |
1037 if ((event.windowsKeyCode == ui::VKEY_ESCAPE) && | |
1038 !(event.modifiers & blink::WebInputEvent::InputModifiers)) { | |
1039 return web_contents()->GotResponseToLockMouseRequest(false); | |
1040 } | |
1041 | |
1042 #if defined(OS_MACOSX) | |
1043 if (event.modifiers != blink::WebInputEvent::MetaKey) | |
1044 return false; | |
1045 | |
1046 if (event.windowsKeyCode == ui::VKEY_OEM_4) { | |
1047 Go(-1); | |
1048 return true; | |
1049 } | |
1050 | |
1051 if (event.windowsKeyCode == ui::VKEY_OEM_6) { | |
1052 Go(1); | |
1053 return true; | |
1054 } | |
1055 #else | |
1056 if (event.windowsKeyCode == ui::VKEY_BROWSER_BACK) { | |
1057 Go(-1); | |
1058 return true; | |
1059 } | |
1060 | |
1061 if (event.windowsKeyCode == ui::VKEY_BROWSER_FORWARD) { | |
1062 Go(1); | |
1063 return true; | |
1064 } | |
1065 #endif | |
1066 | |
1067 return false; | |
1068 } | |
1069 | |
1070 void WebViewGuest::ApplyAttributes(const base::DictionaryValue& params) { | |
1071 std::string name; | |
1072 if (params.GetString(webview::kAttributeName, &name)) { | |
1073 // If the guest window's name is empty, then the WebView tag's name is | |
1074 // assigned. Otherwise, the guest window's name takes precedence over the | |
1075 // WebView tag's name. | |
1076 if (name_.empty()) | |
1077 SetName(name); | |
1078 } | |
1079 if (attached()) | |
1080 ReportFrameNameChange(name_); | |
1081 | |
1082 std::string user_agent_override; | |
1083 params.GetString(webview::kParameterUserAgentOverride, &user_agent_override); | |
1084 SetUserAgentOverride(user_agent_override); | |
1085 | |
1086 bool allow_transparency = false; | |
1087 if (params.GetBoolean(webview::kAttributeAllowTransparency, | |
1088 &allow_transparency)) { | |
1089 // We need to set the background opaque flag after navigation to ensure that | |
1090 // there is a RenderWidgetHostView available. | |
1091 SetAllowTransparency(allow_transparency); | |
1092 } | |
1093 | |
1094 bool allow_scaling = false; | |
1095 if (params.GetBoolean(webview::kAttributeAllowScaling, &allow_scaling)) | |
1096 SetAllowScaling(allow_scaling); | |
1097 | |
1098 // Check for a pending zoom from before the first navigation. | |
1099 params.GetDouble(webview::kInitialZoomFactor, &pending_zoom_factor_); | |
1100 | |
1101 bool is_pending_new_window = false; | |
1102 if (GetOpener()) { | |
1103 // We need to do a navigation here if the target URL has changed between | |
1104 // the time the WebContents was created and the time it was attached. | |
1105 // We also need to do an initial navigation if a RenderView was never | |
1106 // created for the new window in cases where there is no referrer. | |
1107 auto it = GetOpener()->pending_new_windows_.find(this); | |
1108 if (it != GetOpener()->pending_new_windows_.end()) { | |
1109 const NewWindowInfo& new_window_info = it->second; | |
1110 if (new_window_info.changed || !web_contents()->HasOpener()) | |
1111 NavigateGuest(new_window_info.url.spec(), false /* force_navigation */); | |
1112 | |
1113 // Once a new guest is attached to the DOM of the embedder page, then the | |
1114 // lifetime of the new guest is no longer managed by the opener guest. | |
1115 GetOpener()->pending_new_windows_.erase(this); | |
1116 | |
1117 is_pending_new_window = true; | |
1118 } | |
1119 } | |
1120 | |
1121 // Only read the src attribute if this is not a New Window API flow. | |
1122 if (!is_pending_new_window) { | |
1123 std::string src; | |
1124 if (params.GetString(webview::kAttributeSrc, &src)) | |
1125 NavigateGuest(src, true /* force_navigation */); | |
1126 } | |
1127 } | |
1128 | |
1129 void WebViewGuest::ShowContextMenu( | |
1130 int request_id, | |
1131 const WebViewGuestDelegate::MenuItemVector* items) { | |
1132 if (web_view_guest_delegate_) | |
1133 web_view_guest_delegate_->OnShowContextMenu(request_id, items); | |
1134 } | |
1135 | |
1136 void WebViewGuest::SetName(const std::string& name) { | |
1137 if (name_ == name) | |
1138 return; | |
1139 name_ = name; | |
1140 | |
1141 Send(new ExtensionMsg_SetFrameName(routing_id(), name_)); | |
1142 } | |
1143 | |
1144 void WebViewGuest::SetZoom(double zoom_factor) { | |
1145 auto zoom_controller = ZoomController::FromWebContents(web_contents()); | |
1146 DCHECK(zoom_controller); | |
1147 double zoom_level = content::ZoomFactorToZoomLevel(zoom_factor); | |
1148 zoom_controller->SetZoomLevel(zoom_level); | |
1149 } | |
1150 | |
1151 void WebViewGuest::SetZoomMode(ZoomController::ZoomMode zoom_mode) { | |
1152 ZoomController::FromWebContents(web_contents())->SetZoomMode(zoom_mode); | |
1153 } | |
1154 | |
1155 void WebViewGuest::SetAllowTransparency(bool allow) { | |
1156 if (allow_transparency_ == allow) | |
1157 return; | |
1158 | |
1159 allow_transparency_ = allow; | |
1160 if (!web_contents()->GetRenderViewHost()->GetView()) | |
1161 return; | |
1162 | |
1163 if (allow_transparency_) { | |
1164 web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor( | |
1165 SK_ColorTRANSPARENT); | |
1166 } else { | |
1167 web_contents() | |
1168 ->GetRenderViewHost() | |
1169 ->GetView() | |
1170 ->SetBackgroundColorToDefault(); | |
1171 } | |
1172 } | |
1173 | |
1174 void WebViewGuest::SetAllowScaling(bool allow) { | |
1175 allow_scaling_ = allow; | |
1176 } | |
1177 | |
1178 bool WebViewGuest::LoadDataWithBaseURL(const std::string& data_url, | |
1179 const std::string& base_url, | |
1180 const std::string& virtual_url, | |
1181 std::string* error) { | |
1182 // Make GURLs from URLs. | |
1183 const GURL data_gurl = GURL(data_url); | |
1184 const GURL base_gurl = GURL(base_url); | |
1185 const GURL virtual_gurl = GURL(virtual_url); | |
1186 | |
1187 // Check that the provided URLs are valid. | |
1188 // |data_url| must be a valid data URL. | |
1189 if (!data_gurl.is_valid() || !data_gurl.SchemeIs(url::kDataScheme)) { | |
1190 base::SStringPrintf( | |
1191 error, webview::kAPILoadDataInvalidDataURL, data_url.c_str()); | |
1192 return false; | |
1193 } | |
1194 // |base_url| must be a valid URL. | |
1195 if (!base_gurl.is_valid()) { | |
1196 base::SStringPrintf( | |
1197 error, webview::kAPILoadDataInvalidBaseURL, base_url.c_str()); | |
1198 return false; | |
1199 } | |
1200 // |virtual_url| must be a valid URL. | |
1201 if (!virtual_gurl.is_valid()) { | |
1202 base::SStringPrintf( | |
1203 error, webview::kAPILoadDataInvalidVirtualURL, virtual_url.c_str()); | |
1204 return false; | |
1205 } | |
1206 | |
1207 // Set up the parameters to load |data_url| with the specified |base_url|. | |
1208 content::NavigationController::LoadURLParams load_params(data_gurl); | |
1209 load_params.load_type = content::NavigationController::LOAD_TYPE_DATA; | |
1210 load_params.base_url_for_data_url = base_gurl; | |
1211 load_params.virtual_url_for_data_url = virtual_gurl; | |
1212 load_params.override_user_agent = | |
1213 content::NavigationController::UA_OVERRIDE_INHERIT; | |
1214 | |
1215 // Navigate to the data URL. | |
1216 GuestViewBase::LoadURLWithParams(load_params); | |
1217 | |
1218 return true; | |
1219 } | |
1220 | |
1221 void WebViewGuest::AddNewContents(WebContents* source, | 933 void WebViewGuest::AddNewContents(WebContents* source, |
1222 WebContents* new_contents, | 934 WebContents* new_contents, |
1223 WindowOpenDisposition disposition, | 935 WindowOpenDisposition disposition, |
1224 const gfx::Rect& initial_rect, | 936 const gfx::Rect& initial_rect, |
1225 bool user_gesture, | 937 bool user_gesture, |
1226 bool* was_blocked) { | 938 bool* was_blocked) { |
1227 if (was_blocked) | 939 if (was_blocked) |
1228 *was_blocked = false; | 940 *was_blocked = false; |
1229 RequestNewWindowPermission(disposition, | 941 RequestNewWindowPermission(disposition, |
1230 initial_rect, | 942 initial_rect, |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1333 | 1045 |
1334 void WebViewGuest::ExitFullscreenModeForTab(WebContents* web_contents) { | 1046 void WebViewGuest::ExitFullscreenModeForTab(WebContents* web_contents) { |
1335 SetFullscreenState(false); | 1047 SetFullscreenState(false); |
1336 } | 1048 } |
1337 | 1049 |
1338 bool WebViewGuest::IsFullscreenForTabOrPending( | 1050 bool WebViewGuest::IsFullscreenForTabOrPending( |
1339 const WebContents* web_contents) const { | 1051 const WebContents* web_contents) const { |
1340 return is_guest_fullscreen_; | 1052 return is_guest_fullscreen_; |
1341 } | 1053 } |
1342 | 1054 |
| 1055 void WebViewGuest::DidCommitProvisionalLoadForFrame( |
| 1056 content::RenderFrameHost* render_frame_host, |
| 1057 const GURL& url, |
| 1058 ui::PageTransition transition_type) { |
| 1059 if (!render_frame_host->GetParent()) { |
| 1060 src_ = url; |
| 1061 // Handle a pending zoom if one exists. |
| 1062 if (pending_zoom_factor_) { |
| 1063 SetZoom(pending_zoom_factor_); |
| 1064 pending_zoom_factor_ = 0.0; |
| 1065 } |
| 1066 } |
| 1067 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 1068 args->SetString(guest_view::kUrl, url.spec()); |
| 1069 args->SetBoolean(guest_view::kIsTopLevel, !render_frame_host->GetParent()); |
| 1070 args->SetString(webview::kInternalBaseURLForDataURL, |
| 1071 web_contents() |
| 1072 ->GetController() |
| 1073 .GetLastCommittedEntry() |
| 1074 ->GetBaseURLForDataURL() |
| 1075 .spec()); |
| 1076 args->SetInteger(webview::kInternalCurrentEntryIndex, |
| 1077 web_contents()->GetController().GetCurrentEntryIndex()); |
| 1078 args->SetInteger(webview::kInternalEntryCount, |
| 1079 web_contents()->GetController().GetEntryCount()); |
| 1080 args->SetInteger(webview::kInternalProcessId, |
| 1081 web_contents()->GetRenderProcessHost()->GetID()); |
| 1082 DispatchEventToView( |
| 1083 new GuestViewEvent(webview::kEventLoadCommit, args.Pass())); |
| 1084 |
| 1085 find_helper_.CancelAllFindSessions(); |
| 1086 } |
| 1087 |
| 1088 void WebViewGuest::DidFailProvisionalLoad( |
| 1089 content::RenderFrameHost* render_frame_host, |
| 1090 const GURL& validated_url, |
| 1091 int error_code, |
| 1092 const base::string16& error_description, |
| 1093 bool was_ignored_by_handler) { |
| 1094 // Suppress loadabort for "mailto" URLs. |
| 1095 if (validated_url.SchemeIs(url::kMailToScheme)) |
| 1096 return; |
| 1097 |
| 1098 LoadAbort(!render_frame_host->GetParent(), validated_url, error_code, |
| 1099 net::ErrorToShortString(error_code)); |
| 1100 } |
| 1101 |
| 1102 void WebViewGuest::DidStartProvisionalLoadForFrame( |
| 1103 content::RenderFrameHost* render_frame_host, |
| 1104 const GURL& validated_url, |
| 1105 bool is_error_page, |
| 1106 bool is_iframe_srcdoc) { |
| 1107 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 1108 args->SetString(guest_view::kUrl, validated_url.spec()); |
| 1109 args->SetBoolean(guest_view::kIsTopLevel, !render_frame_host->GetParent()); |
| 1110 DispatchEventToView( |
| 1111 new GuestViewEvent(webview::kEventLoadStart, args.Pass())); |
| 1112 } |
| 1113 |
| 1114 void WebViewGuest::RenderProcessGone(base::TerminationStatus status) { |
| 1115 // Cancel all find sessions in progress. |
| 1116 find_helper_.CancelAllFindSessions(); |
| 1117 |
| 1118 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 1119 args->SetInteger(webview::kProcessId, |
| 1120 web_contents()->GetRenderProcessHost()->GetID()); |
| 1121 args->SetString(webview::kReason, TerminationStatusToString(status)); |
| 1122 DispatchEventToView(new GuestViewEvent(webview::kEventExit, args.Pass())); |
| 1123 } |
| 1124 |
| 1125 void WebViewGuest::UserAgentOverrideSet(const std::string& user_agent) { |
| 1126 content::NavigationController& controller = web_contents()->GetController(); |
| 1127 content::NavigationEntry* entry = controller.GetVisibleEntry(); |
| 1128 if (!entry) |
| 1129 return; |
| 1130 entry->SetIsOverridingUserAgent(!user_agent.empty()); |
| 1131 web_contents()->GetController().Reload(false); |
| 1132 } |
| 1133 |
| 1134 void WebViewGuest::FrameNameChanged(RenderFrameHost* render_frame_host, |
| 1135 const std::string& name) { |
| 1136 if (render_frame_host->GetParent()) |
| 1137 return; |
| 1138 |
| 1139 if (name_ == name) |
| 1140 return; |
| 1141 |
| 1142 ReportFrameNameChange(name); |
| 1143 } |
| 1144 |
| 1145 void WebViewGuest::ReportFrameNameChange(const std::string& name) { |
| 1146 name_ = name; |
| 1147 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 1148 args->SetString(webview::kName, name); |
| 1149 DispatchEventToView( |
| 1150 new GuestViewEvent(webview::kEventFrameNameChanged, args.Pass())); |
| 1151 } |
| 1152 |
| 1153 void WebViewGuest::LoadHandlerCalled() { |
| 1154 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 1155 DispatchEventToView( |
| 1156 new GuestViewEvent(webview::kEventContentLoad, args.Pass())); |
| 1157 } |
| 1158 |
| 1159 void WebViewGuest::LoadRedirect(const GURL& old_url, |
| 1160 const GURL& new_url, |
| 1161 bool is_top_level) { |
| 1162 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
| 1163 args->SetBoolean(guest_view::kIsTopLevel, is_top_level); |
| 1164 args->SetString(webview::kNewURL, new_url.spec()); |
| 1165 args->SetString(webview::kOldURL, old_url.spec()); |
| 1166 DispatchEventToView( |
| 1167 new GuestViewEvent(webview::kEventLoadRedirect, args.Pass())); |
| 1168 } |
| 1169 |
| 1170 void WebViewGuest::PushWebViewStateToIOThread() { |
| 1171 const GURL& site_url = web_contents()->GetSiteInstance()->GetSiteURL(); |
| 1172 std::string partition_domain; |
| 1173 std::string partition_id; |
| 1174 bool in_memory; |
| 1175 if (!GetGuestPartitionConfigForSite(site_url, &partition_domain, |
| 1176 &partition_id, &in_memory)) { |
| 1177 NOTREACHED(); |
| 1178 return; |
| 1179 } |
| 1180 |
| 1181 WebViewRendererState::WebViewInfo web_view_info; |
| 1182 web_view_info.embedder_process_id = |
| 1183 owner_web_contents()->GetRenderProcessHost()->GetID(); |
| 1184 web_view_info.instance_id = view_instance_id(); |
| 1185 web_view_info.partition_id = partition_id; |
| 1186 web_view_info.owner_host = owner_host(); |
| 1187 web_view_info.rules_registry_id = rules_registry_id_; |
| 1188 |
| 1189 // Get content scripts IDs added by the guest. |
| 1190 WebViewContentScriptManager* manager = |
| 1191 WebViewContentScriptManager::Get(browser_context()); |
| 1192 DCHECK(manager); |
| 1193 web_view_info.content_script_ids = manager->GetContentScriptIDSet( |
| 1194 web_view_info.embedder_process_id, web_view_info.instance_id); |
| 1195 |
| 1196 content::BrowserThread::PostTask( |
| 1197 content::BrowserThread::IO, FROM_HERE, |
| 1198 base::Bind(&WebViewRendererState::AddGuest, |
| 1199 base::Unretained(WebViewRendererState::GetInstance()), |
| 1200 web_contents()->GetRenderProcessHost()->GetID(), |
| 1201 web_contents()->GetRoutingID(), web_view_info)); |
| 1202 } |
| 1203 |
| 1204 // static |
| 1205 void WebViewGuest::RemoveWebViewStateFromIOThread(WebContents* web_contents) { |
| 1206 content::BrowserThread::PostTask( |
| 1207 content::BrowserThread::IO, FROM_HERE, |
| 1208 base::Bind(&WebViewRendererState::RemoveGuest, |
| 1209 base::Unretained(WebViewRendererState::GetInstance()), |
| 1210 web_contents->GetRenderProcessHost()->GetID(), |
| 1211 web_contents->GetRoutingID())); |
| 1212 } |
| 1213 |
1343 void WebViewGuest::LoadURLWithParams( | 1214 void WebViewGuest::LoadURLWithParams( |
1344 const GURL& url, | 1215 const GURL& url, |
1345 const content::Referrer& referrer, | 1216 const content::Referrer& referrer, |
1346 ui::PageTransition transition_type, | 1217 ui::PageTransition transition_type, |
1347 const GlobalRequestID& transferred_global_request_id, | 1218 const GlobalRequestID& transferred_global_request_id, |
1348 bool force_navigation) { | 1219 bool force_navigation) { |
1349 if (!url.is_valid()) { | 1220 if (!url.is_valid()) { |
1350 LoadAbort(true /* is_top_level */, url, net::ERR_INVALID_URL, | 1221 LoadAbort(true /* is_top_level */, url, net::ERR_INVALID_URL, |
1351 net::ErrorToShortString(net::ERR_INVALID_URL)); | 1222 net::ErrorToShortString(net::ERR_INVALID_URL)); |
1352 NavigateGuest(url::kAboutBlankURL, false /* force_navigation */); | 1223 NavigateGuest(url::kAboutBlankURL, false /* force_navigation */); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1437 IsOwnedByExtension(this)) { | 1308 IsOwnedByExtension(this)) { |
1438 return GURL(src); | 1309 return GURL(src); |
1439 } | 1310 } |
1440 | 1311 |
1441 GURL default_url(base::StringPrintf("%s://%s/", | 1312 GURL default_url(base::StringPrintf("%s://%s/", |
1442 kExtensionScheme, | 1313 kExtensionScheme, |
1443 owner_host().c_str())); | 1314 owner_host().c_str())); |
1444 return default_url.Resolve(src); | 1315 return default_url.Resolve(src); |
1445 } | 1316 } |
1446 | 1317 |
1447 void WebViewGuest::OnWebViewNewWindowResponse( | 1318 void WebViewGuest::LoadAbort(bool is_top_level, |
1448 int new_window_instance_id, | 1319 const GURL& url, |
1449 bool allow, | 1320 int error_code, |
1450 const std::string& user_input) { | 1321 const std::string& error_type) { |
1451 auto guest = | 1322 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
1452 WebViewGuest::From(owner_web_contents()->GetRenderProcessHost()->GetID(), | 1323 args->SetBoolean(guest_view::kIsTopLevel, is_top_level); |
1453 new_window_instance_id); | 1324 args->SetString(guest_view::kUrl, url.possibly_invalid_spec()); |
1454 if (!guest) | 1325 args->SetInteger(guest_view::kCode, error_code); |
1455 return; | 1326 args->SetString(guest_view::kReason, error_type); |
1456 | 1327 DispatchEventToView( |
1457 if (!allow) | 1328 new GuestViewEvent(webview::kEventLoadAbort, args.Pass())); |
1458 guest->Destroy(); | |
1459 } | 1329 } |
1460 | 1330 |
1461 void WebViewGuest::OnFullscreenPermissionDecided( | 1331 void WebViewGuest::CreateNewGuestWebViewWindow( |
1462 bool allowed, | 1332 const content::OpenURLParams& params) { |
1463 const std::string& user_input) { | 1333 GuestViewManager* guest_manager = |
1464 last_fullscreen_permission_was_allowed_by_embedder_ = allowed; | 1334 GuestViewManager::FromBrowserContext(browser_context()); |
1465 SetFullscreenState(allowed); | 1335 // Set the attach params to use the same partition as the opener. |
| 1336 // We pull the partition information from the site's URL, which is of the |
| 1337 // form guest://site/{persist}?{partition_name}. |
| 1338 const GURL& site_url = web_contents()->GetSiteInstance()->GetSiteURL(); |
| 1339 const std::string storage_partition_id = |
| 1340 GetStoragePartitionIdFromSiteURL(site_url); |
| 1341 base::DictionaryValue create_params; |
| 1342 create_params.SetString(webview::kStoragePartitionId, storage_partition_id); |
| 1343 |
| 1344 guest_manager->CreateGuest( |
| 1345 WebViewGuest::Type, embedder_web_contents(), create_params, |
| 1346 base::Bind(&WebViewGuest::NewGuestWebViewCallback, |
| 1347 weak_ptr_factory_.GetWeakPtr(), params)); |
1466 } | 1348 } |
1467 | 1349 |
1468 bool WebViewGuest::GuestMadeEmbedderFullscreen() const { | 1350 void WebViewGuest::NewGuestWebViewCallback(const content::OpenURLParams& params, |
1469 return last_fullscreen_permission_was_allowed_by_embedder_ && | 1351 WebContents* guest_web_contents) { |
1470 is_embedder_fullscreen_; | 1352 WebViewGuest* new_guest = WebViewGuest::FromWebContents(guest_web_contents); |
| 1353 new_guest->SetOpener(this); |
| 1354 |
| 1355 // Take ownership of |new_guest|. |
| 1356 pending_new_windows_.insert( |
| 1357 std::make_pair(new_guest, NewWindowInfo(params.url, std::string()))); |
| 1358 |
| 1359 // Request permission to show the new window. |
| 1360 RequestNewWindowPermission(params.disposition, gfx::Rect(), |
| 1361 params.user_gesture, new_guest->web_contents()); |
1471 } | 1362 } |
1472 | 1363 |
1473 void WebViewGuest::SetFullscreenState(bool is_fullscreen) { | 1364 bool WebViewGuest::HandleKeyboardShortcuts( |
1474 if (is_fullscreen == is_guest_fullscreen_) | 1365 const content::NativeWebKeyboardEvent& event) { |
1475 return; | 1366 // <webview> outside of Chrome Apps do not handle keyboard shortcuts. |
| 1367 if (!GuestViewManager::FromBrowserContext(browser_context()) |
| 1368 ->IsOwnedByExtension(this)) { |
| 1369 return false; |
| 1370 } |
1476 | 1371 |
1477 bool was_fullscreen = is_guest_fullscreen_; | 1372 if (event.type != blink::WebInputEvent::RawKeyDown) |
1478 is_guest_fullscreen_ = is_fullscreen; | 1373 return false; |
1479 // If the embedder entered fullscreen because of us, it should exit fullscreen | 1374 |
1480 // when we exit fullscreen. | 1375 // If the user hits the escape key without any modifiers then unlock the |
1481 if (was_fullscreen && GuestMadeEmbedderFullscreen()) { | 1376 // mouse if necessary. |
1482 // Dispatch a message so we can call document.webkitCancelFullscreen() | 1377 if ((event.windowsKeyCode == ui::VKEY_ESCAPE) && |
1483 // on the embedder. | 1378 !(event.modifiers & blink::WebInputEvent::InputModifiers)) { |
1484 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | 1379 return web_contents()->GotResponseToLockMouseRequest(false); |
1485 DispatchEventToView( | |
1486 new GuestViewEvent(webview::kEventExitFullscreen, args.Pass())); | |
1487 } | 1380 } |
1488 // Since we changed fullscreen state, sending a Resize message ensures that | 1381 |
1489 // renderer/ sees the change. | 1382 #if defined(OS_MACOSX) |
1490 web_contents()->GetRenderViewHost()->WasResized(); | 1383 if (event.modifiers != blink::WebInputEvent::MetaKey) |
| 1384 return false; |
| 1385 |
| 1386 if (event.windowsKeyCode == ui::VKEY_OEM_4) { |
| 1387 Go(-1); |
| 1388 return true; |
| 1389 } |
| 1390 |
| 1391 if (event.windowsKeyCode == ui::VKEY_OEM_6) { |
| 1392 Go(1); |
| 1393 return true; |
| 1394 } |
| 1395 #else |
| 1396 if (event.windowsKeyCode == ui::VKEY_BROWSER_BACK) { |
| 1397 Go(-1); |
| 1398 return true; |
| 1399 } |
| 1400 |
| 1401 if (event.windowsKeyCode == ui::VKEY_BROWSER_FORWARD) { |
| 1402 Go(1); |
| 1403 return true; |
| 1404 } |
| 1405 #endif |
| 1406 |
| 1407 return false; |
| 1408 } |
| 1409 |
| 1410 void WebViewGuest::ApplyAttributes(const base::DictionaryValue& params) { |
| 1411 std::string name; |
| 1412 if (params.GetString(webview::kAttributeName, &name)) { |
| 1413 // If the guest window's name is empty, then the WebView tag's name is |
| 1414 // assigned. Otherwise, the guest window's name takes precedence over the |
| 1415 // WebView tag's name. |
| 1416 if (name_.empty()) |
| 1417 SetName(name); |
| 1418 } |
| 1419 if (attached()) |
| 1420 ReportFrameNameChange(name_); |
| 1421 |
| 1422 std::string user_agent_override; |
| 1423 params.GetString(webview::kParameterUserAgentOverride, &user_agent_override); |
| 1424 SetUserAgentOverride(user_agent_override); |
| 1425 |
| 1426 bool allow_transparency = false; |
| 1427 if (params.GetBoolean(webview::kAttributeAllowTransparency, |
| 1428 &allow_transparency)) { |
| 1429 // We need to set the background opaque flag after navigation to ensure that |
| 1430 // there is a RenderWidgetHostView available. |
| 1431 SetAllowTransparency(allow_transparency); |
| 1432 } |
| 1433 |
| 1434 bool allow_scaling = false; |
| 1435 if (params.GetBoolean(webview::kAttributeAllowScaling, &allow_scaling)) |
| 1436 SetAllowScaling(allow_scaling); |
| 1437 |
| 1438 // Check for a pending zoom from before the first navigation. |
| 1439 params.GetDouble(webview::kInitialZoomFactor, &pending_zoom_factor_); |
| 1440 |
| 1441 bool is_pending_new_window = false; |
| 1442 if (GetOpener()) { |
| 1443 // We need to do a navigation here if the target URL has changed between |
| 1444 // the time the WebContents was created and the time it was attached. |
| 1445 // We also need to do an initial navigation if a RenderView was never |
| 1446 // created for the new window in cases where there is no referrer. |
| 1447 auto it = GetOpener()->pending_new_windows_.find(this); |
| 1448 if (it != GetOpener()->pending_new_windows_.end()) { |
| 1449 const NewWindowInfo& new_window_info = it->second; |
| 1450 if (new_window_info.changed || !web_contents()->HasOpener()) |
| 1451 NavigateGuest(new_window_info.url.spec(), false /* force_navigation */); |
| 1452 |
| 1453 // Once a new guest is attached to the DOM of the embedder page, then the |
| 1454 // lifetime of the new guest is no longer managed by the opener guest. |
| 1455 GetOpener()->pending_new_windows_.erase(this); |
| 1456 |
| 1457 is_pending_new_window = true; |
| 1458 } |
| 1459 } |
| 1460 |
| 1461 // Only read the src attribute if this is not a New Window API flow. |
| 1462 if (!is_pending_new_window) { |
| 1463 std::string src; |
| 1464 if (params.GetString(webview::kAttributeSrc, &src)) |
| 1465 NavigateGuest(src, true /* force_navigation */); |
| 1466 } |
1491 } | 1467 } |
1492 | 1468 |
1493 } // namespace extensions | 1469 } // namespace extensions |
OLD | NEW |