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
3 // found in the LICENSE file.
5 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/public/browser/browser_context.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/child_process_security_policy.h"
13 #include "content/public/browser/native_web_keyboard_event.h"
14 #include "content/public/browser/navigation_entry.h"
15 #include "content/public/browser/notification_details.h"
16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/notification_source.h"
18 #include "content/public/browser/notification_types.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "content/public/browser/render_widget_host_view.h"
22 #include "content/public/browser/resource_request_details.h"
23 #include "content/public/browser/site_instance.h"
24 #include "content/public/browser/storage_partition.h"
25 #include "content/public/browser/user_metrics.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/browser/web_contents_delegate.h"
28 #include "content/public/common/media_stream_request.h"
29 #include "content/public/common/page_zoom.h"
30 #include "content/public/common/result_codes.h"
31 #include "content/public/common/stop_find_action.h"
32 #include "content/public/common/url_constants.h"
33 #include "extensions/browser/api/declarative/rules_registry_service.h"
34 #include "extensions/browser/api/extensions_api_client.h"
35 #include "extensions/browser/api/guest_view/web_view/web_view_internal_api.h"
36 #include "extensions/browser/api/web_request/web_request_api.h"
37 #include "extensions/browser/extension_system.h"
38 #include "extensions/browser/guest_view/guest_view_manager.h"
39 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
40 #include "extensions/browser/guest_view/web_view/web_view_permission_helper.h"
41 #include "extensions/browser/guest_view/web_view/web_view_permission_types.h"
42 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
43 #include "extensions/common/constants.h"
44 #include "extensions/common/extension_messages.h"
45 #include "extensions/common/guest_view/guest_view_constants.h"
46 #include "extensions/strings/grit/extensions_strings.h"
47 #include "ipc/ipc_message_macros.h"
48 #include "net/base/escape.h"
49 #include "net/base/net_errors.h"
50 #include "ui/base/models/simple_menu_model.h"
51 #include "url/url_constants.h"
53 using base::UserMetricsAction
;
54 using content::RenderFrameHost
;
55 using content::ResourceType
;
56 using content::StoragePartition
;
57 using content::WebContents
;
58 using ui_zoom::ZoomController
;
60 namespace extensions
{
64 // Returns storage partition removal mask from web_view clearData mask. Note
65 // that storage partition mask is a subset of webview's data removal mask.
66 uint32
GetStoragePartitionRemovalMask(uint32 web_view_removal_mask
) {
68 if (web_view_removal_mask
& webview::WEB_VIEW_REMOVE_DATA_MASK_APPCACHE
)
69 mask
|= StoragePartition::REMOVE_DATA_MASK_APPCACHE
;
70 if (web_view_removal_mask
& webview::WEB_VIEW_REMOVE_DATA_MASK_COOKIES
)
71 mask
|= StoragePartition::REMOVE_DATA_MASK_COOKIES
;
72 if (web_view_removal_mask
& webview::WEB_VIEW_REMOVE_DATA_MASK_FILE_SYSTEMS
)
73 mask
|= StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS
;
74 if (web_view_removal_mask
& webview::WEB_VIEW_REMOVE_DATA_MASK_INDEXEDDB
)
75 mask
|= StoragePartition::REMOVE_DATA_MASK_INDEXEDDB
;
76 if (web_view_removal_mask
& webview::WEB_VIEW_REMOVE_DATA_MASK_LOCAL_STORAGE
)
77 mask
|= StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE
;
78 if (web_view_removal_mask
& webview::WEB_VIEW_REMOVE_DATA_MASK_WEBSQL
)
79 mask
|= StoragePartition::REMOVE_DATA_MASK_WEBSQL
;
84 std::string
WindowOpenDispositionToString(
85 WindowOpenDisposition window_open_disposition
) {
86 switch (window_open_disposition
) {
90 return "save_to_disk";
93 case NEW_BACKGROUND_TAB
:
94 return "new_background_tab";
95 case NEW_FOREGROUND_TAB
:
96 return "new_foreground_tab";
102 NOTREACHED() << "Unknown Window Open Disposition";
107 static std::string
TerminationStatusToString(base::TerminationStatus status
) {
109 case base::TERMINATION_STATUS_NORMAL_TERMINATION
:
111 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION
:
112 case base::TERMINATION_STATUS_STILL_RUNNING
:
114 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED
:
116 case base::TERMINATION_STATUS_PROCESS_CRASHED
:
118 case base::TERMINATION_STATUS_MAX_ENUM
:
121 NOTREACHED() << "Unknown Termination Status.";
125 std::string
GetStoragePartitionIdFromSiteURL(const GURL
& site_url
) {
126 const std::string
& partition_id
= site_url
.query();
127 bool persist_storage
= site_url
.path().find("persist") != std::string::npos
;
128 return (persist_storage
? webview::kPersistPrefix
: "") + partition_id
;
131 void ParsePartitionParam(const base::DictionaryValue
& create_params
,
132 std::string
* storage_partition_id
,
133 bool* persist_storage
) {
134 std::string partition_str
;
135 if (!create_params
.GetString(webview::kStoragePartitionId
, &partition_str
)) {
139 // Since the "persist:" prefix is in ASCII, StartsWith will work fine on
140 // UTF-8 encoded |partition_id|. If the prefix is a match, we can safely
141 // remove the prefix without splicing in the middle of a multi-byte codepoint.
142 // We can use the rest of the string as UTF-8 encoded one.
143 if (StartsWithASCII(partition_str
, "persist:", true)) {
144 size_t index
= partition_str
.find(":");
145 CHECK(index
!= std::string::npos
);
146 // It is safe to do index + 1, since we tested for the full prefix above.
147 *storage_partition_id
= partition_str
.substr(index
+ 1);
149 if (storage_partition_id
->empty()) {
150 // TODO(lazyboy): Better way to deal with this error.
153 *persist_storage
= true;
155 *storage_partition_id
= partition_str
;
156 *persist_storage
= false;
160 void RemoveWebViewEventListenersOnIOThread(
162 const std::string
& extension_id
,
163 int embedder_process_id
,
164 int view_instance_id
) {
165 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO
));
166 ExtensionWebRequestEventRouter::GetInstance()->RemoveWebViewEventListeners(
173 double ConvertZoomLevelToZoomFactor(double zoom_level
) {
174 double zoom_factor
= content::ZoomLevelToZoomFactor(zoom_level
);
175 // Because the conversion from zoom level to zoom factor isn't perfect, the
176 // resulting zoom factor is rounded to the nearest 6th decimal place.
177 zoom_factor
= round(zoom_factor
* 1000000) / 1000000;
184 GuestViewBase
* WebViewGuest::Create(content::WebContents
* owner_web_contents
) {
185 return new WebViewGuest(owner_web_contents
);
189 bool WebViewGuest::GetGuestPartitionConfigForSite(
191 std::string
* partition_domain
,
192 std::string
* partition_name
,
194 if (!site
.SchemeIs(content::kGuestScheme
))
197 // Since guest URLs are only used for packaged apps, there must be an app
199 CHECK(site
.has_host());
200 *partition_domain
= site
.host();
201 // Since persistence is optional, the path must either be empty or the
203 *in_memory
= (site
.path() != "/persist");
204 // The partition name is user supplied value, which we have encoded when the
205 // URL was created, so it needs to be decoded.
207 net::UnescapeURLComponent(site
.query(), net::UnescapeRule::NORMAL
);
212 const char WebViewGuest::Type
[] = "webview";
214 using WebViewKey
= std::pair
<int, int>;
215 using WebViewKeyToIDMap
= std::map
<WebViewKey
, int>;
216 static base::LazyInstance
<WebViewKeyToIDMap
> web_view_key_to_id_map
=
217 LAZY_INSTANCE_INITIALIZER
;
220 int WebViewGuest::GetOrGenerateRulesRegistryID(
221 int embedder_process_id
,
222 int webview_instance_id
) {
223 bool is_web_view
= embedder_process_id
&& webview_instance_id
;
225 return RulesRegistryService::kDefaultRulesRegistryID
;
227 WebViewKey key
= std::make_pair(embedder_process_id
, webview_instance_id
);
228 auto it
= web_view_key_to_id_map
.Get().find(key
);
229 if (it
!= web_view_key_to_id_map
.Get().end())
232 auto rph
= content::RenderProcessHost::FromID(embedder_process_id
);
233 int rules_registry_id
=
234 RulesRegistryService::Get(rph
->GetBrowserContext())->
235 GetNextRulesRegistryID();
236 web_view_key_to_id_map
.Get()[key
] = rules_registry_id
;
237 return rules_registry_id
;
241 int WebViewGuest::GetViewInstanceId(WebContents
* contents
) {
242 auto guest
= FromWebContents(contents
);
244 return guestview::kInstanceIDNone
;
246 return guest
->view_instance_id();
249 bool WebViewGuest::CanRunInDetachedState() const {
253 void WebViewGuest::CreateWebContents(
254 const base::DictionaryValue
& create_params
,
255 const WebContentsCreatedCallback
& callback
) {
256 content::RenderProcessHost
* owner_render_process_host
=
257 owner_web_contents()->GetRenderProcessHost();
258 std::string storage_partition_id
;
259 bool persist_storage
= false;
260 ParsePartitionParam(create_params
, &storage_partition_id
, &persist_storage
);
261 // Validate that the partition id coming from the renderer is valid UTF-8,
262 // since we depend on this in other parts of the code, such as FilePath
263 // creation. If the validation fails, treat it as a bad message and kill the
265 if (!base::IsStringUTF8(storage_partition_id
)) {
266 content::RecordAction(
267 base::UserMetricsAction("BadMessageTerminate_BPGM"));
268 owner_render_process_host
->Shutdown(content::RESULT_CODE_KILLED_BAD_MESSAGE
,
270 callback
.Run(nullptr);
273 std::string url_encoded_partition
= net::EscapeQueryParamValue(
274 storage_partition_id
, false);
275 std::string partition_domain
= GetOwnerSiteURL().host();
276 GURL
guest_site(base::StringPrintf("%s://%s/%s?%s",
277 content::kGuestScheme
,
278 partition_domain
.c_str(),
279 persist_storage
? "persist" : "",
280 url_encoded_partition
.c_str()));
282 // If we already have a webview tag in the same app using the same storage
283 // partition, we should use the same SiteInstance so the existing tag and
284 // the new tag can script each other.
285 auto guest_view_manager
= GuestViewManager::FromBrowserContext(
286 owner_render_process_host
->GetBrowserContext());
287 content::SiteInstance
* guest_site_instance
=
288 guest_view_manager
->GetGuestSiteInstance(guest_site
);
289 if (!guest_site_instance
) {
290 // Create the SiteInstance in a new BrowsingInstance, which will ensure
291 // that webview tags are also not allowed to send messages across
292 // different partitions.
293 guest_site_instance
= content::SiteInstance::CreateForURL(
294 owner_render_process_host
->GetBrowserContext(), guest_site
);
296 WebContents::CreateParams
params(
297 owner_render_process_host
->GetBrowserContext(),
298 guest_site_instance
);
299 params
.guest_delegate
= this;
300 callback
.Run(WebContents::Create(params
));
303 void WebViewGuest::DidAttachToEmbedder() {
304 ApplyAttributes(*attach_params());
307 void WebViewGuest::DidDropLink(const GURL
& url
) {
308 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
309 args
->SetString(guestview::kUrl
, url
.spec());
311 new GuestViewBase::Event(webview::kEventDropLink
, args
.Pass()));
314 void WebViewGuest::DidInitialize(const base::DictionaryValue
& create_params
) {
315 script_executor_
.reset(
316 new ScriptExecutor(web_contents(), &script_observers_
));
318 notification_registrar_
.Add(this,
319 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
,
320 content::Source
<WebContents
>(web_contents()));
322 notification_registrar_
.Add(this,
323 content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT
,
324 content::Source
<WebContents
>(web_contents()));
326 if (web_view_guest_delegate_
)
327 web_view_guest_delegate_
->OnDidInitialize();
328 AttachWebViewHelpers(web_contents());
330 rules_registry_id_
= GetOrGenerateRulesRegistryID(
331 owner_web_contents()->GetRenderProcessHost()->GetID(),
334 // We must install the mapping from guests to WebViews prior to resuming
335 // suspended resource loads so that the WebRequest API will catch resource
337 PushWebViewStateToIOThread();
339 ApplyAttributes(create_params
);
342 void WebViewGuest::AttachWebViewHelpers(WebContents
* contents
) {
343 if (web_view_guest_delegate_
)
344 web_view_guest_delegate_
->OnAttachWebViewHelpers(contents
);
345 web_view_permission_helper_
.reset(new WebViewPermissionHelper(this));
348 void WebViewGuest::ClearDataInternal(base::Time remove_since
,
350 const base::Closure
& callback
) {
351 uint32 storage_partition_removal_mask
=
352 GetStoragePartitionRemovalMask(removal_mask
);
353 if (!storage_partition_removal_mask
) {
357 content::StoragePartition
* partition
=
358 content::BrowserContext::GetStoragePartition(
359 web_contents()->GetBrowserContext(),
360 web_contents()->GetSiteInstance());
361 partition
->ClearData(
362 storage_partition_removal_mask
,
363 content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL
, GURL(),
364 content::StoragePartition::OriginMatcherFunction(), remove_since
,
365 base::Time::Now(), callback
);
368 void WebViewGuest::GuestViewDidStopLoading() {
369 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
371 new GuestViewBase::Event(webview::kEventLoadStop
, args
.Pass()));
374 void WebViewGuest::EmbedderFullscreenToggled(bool entered_fullscreen
) {
375 is_embedder_fullscreen_
= entered_fullscreen
;
376 // If the embedder has got out of fullscreen, we get out of fullscreen
378 if (!entered_fullscreen
)
379 SetFullscreenState(false);
382 void WebViewGuest::EmbedderWillBeDestroyed() {
383 // Clean up rules registries for the webview.
384 RulesRegistryService::Get(browser_context())
385 ->RemoveRulesRegistriesByID(rules_registry_id_
);
386 WebViewKey
key(owner_web_contents()->GetRenderProcessHost()->GetID(),
388 web_view_key_to_id_map
.Get().erase(key
);
390 content::BrowserThread::PostTask(
391 content::BrowserThread::IO
,
394 &RemoveWebViewEventListenersOnIOThread
,
396 owner_extension_id(),
397 owner_web_contents()->GetRenderProcessHost()->GetID(),
398 view_instance_id()));
401 const char* WebViewGuest::GetAPINamespace() const {
402 return webview::kAPINamespace
;
405 int WebViewGuest::GetTaskPrefix() const {
406 return IDS_EXTENSION_TASK_MANAGER_WEBVIEW_TAG_PREFIX
;
409 void WebViewGuest::GuestDestroyed() {
410 // Clean up custom context menu items for this guest.
411 if (web_view_guest_delegate_
)
412 web_view_guest_delegate_
->OnGuestDestroyed();
413 RemoveWebViewStateFromIOThread(web_contents());
416 void WebViewGuest::GuestReady() {
417 // The guest RenderView should always live in an isolated guest process.
418 CHECK(web_contents()->GetRenderProcessHost()->IsIsolatedGuest());
419 Send(new ExtensionMsg_SetFrameName(web_contents()->GetRoutingID(), name_
));
421 // We don't want to accidentally set the opacity of an interstitial page.
422 // WebContents::GetRenderWidgetHostView will return the RWHV of an
423 // interstitial page if one is showing at this time. We only want opacity
424 // to apply to web pages.
427 ->GetRenderViewHost()
429 ->SetBackgroundColorToDefault();
431 web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor(
432 SK_ColorTRANSPARENT
);
436 void WebViewGuest::GuestSizeChangedDueToAutoSize(const gfx::Size
& old_size
,
437 const gfx::Size
& new_size
) {
438 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
439 args
->SetInteger(webview::kOldHeight
, old_size
.height());
440 args
->SetInteger(webview::kOldWidth
, old_size
.width());
441 args
->SetInteger(webview::kNewHeight
, new_size
.height());
442 args
->SetInteger(webview::kNewWidth
, new_size
.width());
444 new GuestViewBase::Event(webview::kEventSizeChanged
, args
.Pass()));
447 bool WebViewGuest::IsAutoSizeSupported() const {
451 bool WebViewGuest::IsDragAndDropEnabled() const {
455 void WebViewGuest::GuestZoomChanged(double old_zoom_level
,
456 double new_zoom_level
) {
457 // Dispatch the zoomchange event.
458 double old_zoom_factor
= ConvertZoomLevelToZoomFactor(old_zoom_level
);
459 double new_zoom_factor
= ConvertZoomLevelToZoomFactor(new_zoom_level
);
460 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
461 args
->SetDouble(webview::kOldZoomFactor
, old_zoom_factor
);
462 args
->SetDouble(webview::kNewZoomFactor
, new_zoom_factor
);
464 new GuestViewBase::Event(webview::kEventZoomChange
, args
.Pass()));
467 void WebViewGuest::WillDestroy() {
468 if (!attached() && GetOpener())
469 GetOpener()->pending_new_windows_
.erase(this);
472 bool WebViewGuest::AddMessageToConsole(WebContents
* source
,
474 const base::string16
& message
,
476 const base::string16
& source_id
) {
477 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
478 // Log levels are from base/logging.h: LogSeverity.
479 args
->SetInteger(webview::kLevel
, level
);
480 args
->SetString(webview::kMessage
, message
);
481 args
->SetInteger(webview::kLine
, line_no
);
482 args
->SetString(webview::kSourceId
, source_id
);
484 new GuestViewBase::Event(webview::kEventConsoleMessage
, args
.Pass()));
488 void WebViewGuest::CloseContents(WebContents
* source
) {
489 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
491 new GuestViewBase::Event(webview::kEventClose
, args
.Pass()));
494 void WebViewGuest::FindReply(WebContents
* source
,
496 int number_of_matches
,
497 const gfx::Rect
& selection_rect
,
498 int active_match_ordinal
,
500 find_helper_
.FindReply(request_id
,
503 active_match_ordinal
,
507 double WebViewGuest::GetZoom() const {
509 ZoomController::FromWebContents(web_contents())->GetZoomLevel();
510 return ConvertZoomLevelToZoomFactor(zoom_level
);
513 ZoomController::ZoomMode
WebViewGuest::GetZoomMode() {
514 return ZoomController::FromWebContents(web_contents())->zoom_mode();
517 bool WebViewGuest::HandleContextMenu(
518 const content::ContextMenuParams
& params
) {
519 if (!web_view_guest_delegate_
)
521 return web_view_guest_delegate_
->HandleContextMenu(params
);
524 void WebViewGuest::HandleKeyboardEvent(
526 const content::NativeWebKeyboardEvent
& event
) {
527 if (HandleKeyboardShortcuts(event
))
530 GuestViewBase::HandleKeyboardEvent(source
, event
);
533 bool WebViewGuest::PreHandleGestureEvent(content::WebContents
* source
,
534 const blink::WebGestureEvent
& event
) {
535 return !allow_scaling_
&& GuestViewBase::PreHandleGestureEvent(source
, event
);
538 void WebViewGuest::LoadProgressChanged(content::WebContents
* source
,
540 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
541 args
->SetString(guestview::kUrl
, web_contents()->GetURL().spec());
542 args
->SetDouble(webview::kProgress
, progress
);
544 new GuestViewBase::Event(webview::kEventLoadProgress
, args
.Pass()));
547 void WebViewGuest::LoadAbort(bool is_top_level
,
549 const std::string
& error_type
) {
550 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
551 args
->SetBoolean(guestview::kIsTopLevel
, is_top_level
);
552 args
->SetString(guestview::kUrl
, url
.possibly_invalid_spec());
553 args
->SetString(guestview::kReason
, error_type
);
555 new GuestViewBase::Event(webview::kEventLoadAbort
, args
.Pass()));
558 void WebViewGuest::CreateNewGuestWebViewWindow(
559 const content::OpenURLParams
& params
) {
560 GuestViewManager
* guest_manager
=
561 GuestViewManager::FromBrowserContext(browser_context());
562 // Set the attach params to use the same partition as the opener.
563 // We pull the partition information from the site's URL, which is of the
564 // form guest://site/{persist}?{partition_name}.
565 const GURL
& site_url
= web_contents()->GetSiteInstance()->GetSiteURL();
566 const std::string storage_partition_id
=
567 GetStoragePartitionIdFromSiteURL(site_url
);
568 base::DictionaryValue create_params
;
569 create_params
.SetString(webview::kStoragePartitionId
, storage_partition_id
);
571 guest_manager
->CreateGuest(WebViewGuest::Type
,
572 embedder_web_contents(),
574 base::Bind(&WebViewGuest::NewGuestWebViewCallback
,
575 weak_ptr_factory_
.GetWeakPtr(),
579 void WebViewGuest::NewGuestWebViewCallback(
580 const content::OpenURLParams
& params
,
581 content::WebContents
* guest_web_contents
) {
582 WebViewGuest
* new_guest
= WebViewGuest::FromWebContents(guest_web_contents
);
583 new_guest
->SetOpener(this);
585 // Take ownership of |new_guest|.
586 pending_new_windows_
.insert(
587 std::make_pair(new_guest
, NewWindowInfo(params
.url
, std::string())));
589 // Request permission to show the new window.
590 RequestNewWindowPermission(params
.disposition
,
593 new_guest
->web_contents());
596 // TODO(fsamuel): Find a reliable way to test the 'responsive' and
597 // 'unresponsive' events.
598 void WebViewGuest::RendererResponsive(content::WebContents
* source
) {
599 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
600 args
->SetInteger(webview::kProcessId
,
601 web_contents()->GetRenderProcessHost()->GetID());
603 new GuestViewBase::Event(webview::kEventResponsive
, args
.Pass()));
606 void WebViewGuest::RendererUnresponsive(content::WebContents
* source
) {
607 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
608 args
->SetInteger(webview::kProcessId
,
609 web_contents()->GetRenderProcessHost()->GetID());
611 new GuestViewBase::Event(webview::kEventUnresponsive
, args
.Pass()));
614 void WebViewGuest::Observe(int type
,
615 const content::NotificationSource
& source
,
616 const content::NotificationDetails
& details
) {
618 case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
: {
619 DCHECK_EQ(content::Source
<WebContents
>(source
).ptr(), web_contents());
620 if (content::Source
<WebContents
>(source
).ptr() == web_contents())
624 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT
: {
625 DCHECK_EQ(content::Source
<WebContents
>(source
).ptr(), web_contents());
626 content::ResourceRedirectDetails
* resource_redirect_details
=
627 content::Details
<content::ResourceRedirectDetails
>(details
).ptr();
628 bool is_top_level
= resource_redirect_details
->resource_type
==
629 content::RESOURCE_TYPE_MAIN_FRAME
;
630 LoadRedirect(resource_redirect_details
->url
,
631 resource_redirect_details
->new_url
,
636 NOTREACHED() << "Unexpected notification sent.";
641 void WebViewGuest::StartFindInternal(
642 const base::string16
& search_text
,
643 const blink::WebFindOptions
& options
,
644 scoped_refptr
<WebViewInternalFindFunction
> find_function
) {
645 find_helper_
.Find(web_contents(), search_text
, options
, find_function
);
648 void WebViewGuest::StopFindingInternal(content::StopFindAction action
) {
649 find_helper_
.CancelAllFindSessions();
650 web_contents()->StopFinding(action
);
653 bool WebViewGuest::Go(int relative_index
) {
654 content::NavigationController
& controller
= web_contents()->GetController();
655 if (!controller
.CanGoToOffset(relative_index
))
658 controller
.GoToOffset(relative_index
);
662 void WebViewGuest::Reload() {
663 // TODO(fsamuel): Don't check for repost because we don't want to show
664 // Chromium's repost warning. We might want to implement a separate API
665 // for registering a callback if a repost is about to happen.
666 web_contents()->GetController().Reload(false);
669 void WebViewGuest::SetUserAgentOverride(
670 const std::string
& user_agent_override
) {
671 is_overriding_user_agent_
= !user_agent_override
.empty();
672 if (is_overriding_user_agent_
) {
673 content::RecordAction(UserMetricsAction("WebView.Guest.OverrideUA"));
675 web_contents()->SetUserAgentOverride(user_agent_override
);
678 void WebViewGuest::Stop() {
679 web_contents()->Stop();
682 void WebViewGuest::Terminate() {
683 content::RecordAction(UserMetricsAction("WebView.Guest.Terminate"));
684 base::ProcessHandle process_handle
=
685 web_contents()->GetRenderProcessHost()->GetHandle();
687 web_contents()->GetRenderProcessHost()->Shutdown(
688 content::RESULT_CODE_KILLED
, false);
691 bool WebViewGuest::ClearData(base::Time remove_since
,
693 const base::Closure
& callback
) {
694 content::RecordAction(UserMetricsAction("WebView.Guest.ClearData"));
695 content::StoragePartition
* partition
=
696 content::BrowserContext::GetStoragePartition(
697 web_contents()->GetBrowserContext(),
698 web_contents()->GetSiteInstance());
703 if (removal_mask
& webview::WEB_VIEW_REMOVE_DATA_MASK_CACHE
) {
704 if (web_view_guest_delegate_
) {
705 // First clear http cache data and then clear the rest in
706 // |ClearDataInternal|.
707 web_view_guest_delegate_
->ClearCache(
708 remove_since
, base::Bind(&WebViewGuest::ClearDataInternal
,
709 weak_ptr_factory_
.GetWeakPtr(), remove_since
,
710 removal_mask
, callback
));
715 ClearDataInternal(remove_since
, removal_mask
, callback
);
719 WebViewGuest::WebViewGuest(content::WebContents
* owner_web_contents
)
720 : GuestView
<WebViewGuest
>(owner_web_contents
),
721 rules_registry_id_(RulesRegistryService::kInvalidRulesRegistryID
),
723 is_overriding_user_agent_(false),
725 javascript_dialog_helper_(this),
726 allow_scaling_(false),
727 is_guest_fullscreen_(false),
728 is_embedder_fullscreen_(false),
729 last_fullscreen_permission_was_allowed_by_embedder_(false),
730 weak_ptr_factory_(this) {
731 web_view_guest_delegate_
.reset(
732 ExtensionsAPIClient::Get()->CreateWebViewGuestDelegate(this));
735 WebViewGuest::~WebViewGuest() {
738 void WebViewGuest::DidCommitProvisionalLoadForFrame(
739 content::RenderFrameHost
* render_frame_host
,
741 ui::PageTransition transition_type
) {
742 if (!render_frame_host
->GetParent())
744 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
745 args
->SetString(guestview::kUrl
, url
.spec());
746 args
->SetBoolean(guestview::kIsTopLevel
, !render_frame_host
->GetParent());
747 args
->SetString(webview::kInternalBaseURLForDataURL
,
750 .GetLastCommittedEntry()
751 ->GetBaseURLForDataURL()
753 args
->SetInteger(webview::kInternalCurrentEntryIndex
,
754 web_contents()->GetController().GetCurrentEntryIndex());
755 args
->SetInteger(webview::kInternalEntryCount
,
756 web_contents()->GetController().GetEntryCount());
757 args
->SetInteger(webview::kInternalProcessId
,
758 web_contents()->GetRenderProcessHost()->GetID());
760 new GuestViewBase::Event(webview::kEventLoadCommit
, args
.Pass()));
762 find_helper_
.CancelAllFindSessions();
764 if (web_view_guest_delegate_
) {
765 web_view_guest_delegate_
->OnDidCommitProvisionalLoadForFrame(
766 !render_frame_host
->GetParent());
770 void WebViewGuest::DidFailProvisionalLoad(
771 content::RenderFrameHost
* render_frame_host
,
772 const GURL
& validated_url
,
774 const base::string16
& error_description
) {
775 LoadAbort(!render_frame_host
->GetParent(), validated_url
,
776 net::ErrorToShortString(error_code
));
779 void WebViewGuest::DidStartProvisionalLoadForFrame(
780 content::RenderFrameHost
* render_frame_host
,
781 const GURL
& validated_url
,
783 bool is_iframe_srcdoc
) {
784 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
785 args
->SetString(guestview::kUrl
, validated_url
.spec());
786 args
->SetBoolean(guestview::kIsTopLevel
, !render_frame_host
->GetParent());
788 new GuestViewBase::Event(webview::kEventLoadStart
, args
.Pass()));
791 void WebViewGuest::DocumentLoadedInFrame(
792 content::RenderFrameHost
* render_frame_host
) {
793 if (web_view_guest_delegate_
)
794 web_view_guest_delegate_
->OnDocumentLoadedInFrame(render_frame_host
);
797 void WebViewGuest::RenderProcessGone(base::TerminationStatus status
) {
798 // Cancel all find sessions in progress.
799 find_helper_
.CancelAllFindSessions();
801 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
802 args
->SetInteger(webview::kProcessId
,
803 web_contents()->GetRenderProcessHost()->GetID());
804 args
->SetString(webview::kReason
, TerminationStatusToString(status
));
806 new GuestViewBase::Event(webview::kEventExit
, args
.Pass()));
809 void WebViewGuest::UserAgentOverrideSet(const std::string
& user_agent
) {
810 content::NavigationController
& controller
= web_contents()->GetController();
811 content::NavigationEntry
* entry
= controller
.GetVisibleEntry();
814 entry
->SetIsOverridingUserAgent(!user_agent
.empty());
815 web_contents()->GetController().Reload(false);
818 void WebViewGuest::FrameNameChanged(RenderFrameHost
* render_frame_host
,
819 const std::string
& name
) {
820 if (render_frame_host
->GetParent())
826 ReportFrameNameChange(name
);
829 void WebViewGuest::ReportFrameNameChange(const std::string
& name
) {
831 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
832 args
->SetString(webview::kName
, name
);
834 new GuestViewBase::Event(webview::kEventFrameNameChanged
, args
.Pass()));
837 void WebViewGuest::LoadHandlerCalled() {
838 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
840 new GuestViewBase::Event(webview::kEventContentLoad
, args
.Pass()));
843 void WebViewGuest::LoadRedirect(const GURL
& old_url
,
846 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
847 args
->SetBoolean(guestview::kIsTopLevel
, is_top_level
);
848 args
->SetString(webview::kNewURL
, new_url
.spec());
849 args
->SetString(webview::kOldURL
, old_url
.spec());
851 new GuestViewBase::Event(webview::kEventLoadRedirect
, args
.Pass()));
854 void WebViewGuest::PushWebViewStateToIOThread() {
855 const GURL
& site_url
= web_contents()->GetSiteInstance()->GetSiteURL();
856 std::string partition_domain
;
857 std::string partition_id
;
859 if (!GetGuestPartitionConfigForSite(
860 site_url
, &partition_domain
, &partition_id
, &in_memory
)) {
865 WebViewRendererState::WebViewInfo web_view_info
;
866 web_view_info
.embedder_process_id
=
867 owner_web_contents()->GetRenderProcessHost()->GetID();
868 web_view_info
.instance_id
= view_instance_id();
869 web_view_info
.partition_id
= partition_id
;
870 web_view_info
.owner_extension_id
= owner_extension_id();
871 web_view_info
.rules_registry_id
= rules_registry_id_
;
873 content::BrowserThread::PostTask(
874 content::BrowserThread::IO
,
876 base::Bind(&WebViewRendererState::AddGuest
,
877 base::Unretained(WebViewRendererState::GetInstance()),
878 web_contents()->GetRenderProcessHost()->GetID(),
879 web_contents()->GetRoutingID(),
884 void WebViewGuest::RemoveWebViewStateFromIOThread(
885 WebContents
* web_contents
) {
886 content::BrowserThread::PostTask(
887 content::BrowserThread::IO
, FROM_HERE
,
889 &WebViewRendererState::RemoveGuest
,
890 base::Unretained(WebViewRendererState::GetInstance()),
891 web_contents
->GetRenderProcessHost()->GetID(),
892 web_contents
->GetRoutingID()));
895 void WebViewGuest::RequestMediaAccessPermission(
896 content::WebContents
* source
,
897 const content::MediaStreamRequest
& request
,
898 const content::MediaResponseCallback
& callback
) {
899 web_view_permission_helper_
->RequestMediaAccessPermission(source
,
904 bool WebViewGuest::CheckMediaAccessPermission(content::WebContents
* source
,
905 const GURL
& security_origin
,
906 content::MediaStreamType type
) {
907 return web_view_permission_helper_
->CheckMediaAccessPermission(
908 source
, security_origin
, type
);
911 void WebViewGuest::CanDownload(
912 content::RenderViewHost
* render_view_host
,
914 const std::string
& request_method
,
915 const base::Callback
<void(bool)>& callback
) {
916 web_view_permission_helper_
->CanDownload(render_view_host
,
922 void WebViewGuest::RequestPointerLockPermission(
924 bool last_unlocked_by_target
,
925 const base::Callback
<void(bool)>& callback
) {
926 web_view_permission_helper_
->RequestPointerLockPermission(
928 last_unlocked_by_target
,
932 void WebViewGuest::WillAttachToEmbedder() {
933 rules_registry_id_
= GetOrGenerateRulesRegistryID(
934 owner_web_contents()->GetRenderProcessHost()->GetID(),
937 // We must install the mapping from guests to WebViews prior to resuming
938 // suspended resource loads so that the WebRequest API will catch resource
940 PushWebViewStateToIOThread();
943 content::JavaScriptDialogManager
* WebViewGuest::GetJavaScriptDialogManager(
944 WebContents
* source
) {
945 return &javascript_dialog_helper_
;
948 void WebViewGuest::NavigateGuest(const std::string
& src
,
949 bool force_navigation
) {
953 GURL url
= ResolveURL(src
);
955 LoadURLWithParams(url
, content::Referrer(),
956 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
960 bool WebViewGuest::HandleKeyboardShortcuts(
961 const content::NativeWebKeyboardEvent
& event
) {
962 // <webview> outside of Chrome Apps do not handle keyboard shortcuts.
966 if (event
.type
!= blink::WebInputEvent::RawKeyDown
)
969 // If the user hits the escape key without any modifiers then unlock the
970 // mouse if necessary.
971 if ((event
.windowsKeyCode
== ui::VKEY_ESCAPE
) &&
972 !(event
.modifiers
& blink::WebInputEvent::InputModifiers
)) {
973 return web_contents()->GotResponseToLockMouseRequest(false);
976 #if defined(OS_MACOSX)
977 if (event
.modifiers
!= blink::WebInputEvent::MetaKey
)
980 if (event
.windowsKeyCode
== ui::VKEY_OEM_4
) {
985 if (event
.windowsKeyCode
== ui::VKEY_OEM_6
) {
990 if (event
.windowsKeyCode
== ui::VKEY_BROWSER_BACK
) {
995 if (event
.windowsKeyCode
== ui::VKEY_BROWSER_FORWARD
) {
1004 void WebViewGuest::ApplyAttributes(const base::DictionaryValue
& params
) {
1006 if (params
.GetString(webview::kAttributeName
, &name
)) {
1007 // If the guest window's name is empty, then the WebView tag's name is
1008 // assigned. Otherwise, the guest window's name takes precedence over the
1009 // WebView tag's name.
1014 ReportFrameNameChange(name_
);
1016 std::string user_agent_override
;
1017 params
.GetString(webview::kParameterUserAgentOverride
, &user_agent_override
);
1018 SetUserAgentOverride(user_agent_override
);
1020 bool allow_transparency
= false;
1021 params
.GetBoolean(webview::kAttributeAllowTransparency
, &allow_transparency
);
1022 // We need to set the background opaque flag after navigation to ensure that
1023 // there is a RenderWidgetHostView available.
1024 SetAllowTransparency(allow_transparency
);
1026 bool allow_scaling
= false;
1027 params
.GetBoolean(webview::kAttributeAllowScaling
, &allow_scaling
);
1028 SetAllowScaling(allow_scaling
);
1030 bool is_pending_new_window
= false;
1032 // We need to do a navigation here if the target URL has changed between
1033 // the time the WebContents was created and the time it was attached.
1034 // We also need to do an initial navigation if a RenderView was never
1035 // created for the new window in cases where there is no referrer.
1036 auto it
= GetOpener()->pending_new_windows_
.find(this);
1037 if (it
!= GetOpener()->pending_new_windows_
.end()) {
1038 const NewWindowInfo
& new_window_info
= it
->second
;
1039 if (new_window_info
.changed
|| !web_contents()->HasOpener())
1040 NavigateGuest(new_window_info
.url
.spec(), false /* force_navigation */);
1042 // Once a new guest is attached to the DOM of the embedder page, then the
1043 // lifetime of the new guest is no longer managed by the opener guest.
1044 GetOpener()->pending_new_windows_
.erase(this);
1046 is_pending_new_window
= true;
1050 // Only read the src attribute if this is not a New Window API flow.
1051 if (!is_pending_new_window
) {
1053 params
.GetString(webview::kAttributeSrc
, &src
);
1054 NavigateGuest(src
, false /* force_navigation */);
1058 void WebViewGuest::ShowContextMenu(
1060 const WebViewGuestDelegate::MenuItemVector
* items
) {
1061 if (web_view_guest_delegate_
)
1062 web_view_guest_delegate_
->OnShowContextMenu(request_id
, items
);
1065 void WebViewGuest::SetName(const std::string
& name
) {
1070 Send(new ExtensionMsg_SetFrameName(routing_id(), name_
));
1073 void WebViewGuest::SetZoom(double zoom_factor
) {
1074 auto zoom_controller
= ZoomController::FromWebContents(web_contents());
1075 DCHECK(zoom_controller
);
1076 double zoom_level
= content::ZoomFactorToZoomLevel(zoom_factor
);
1077 zoom_controller
->SetZoomLevel(zoom_level
);
1080 void WebViewGuest::SetZoomMode(ZoomController::ZoomMode zoom_mode
) {
1081 ZoomController::FromWebContents(web_contents())->SetZoomMode(zoom_mode
);
1084 void WebViewGuest::SetAllowTransparency(bool allow
) {
1085 if (guest_opaque_
!= allow
)
1088 guest_opaque_
= !allow
;
1089 if (!web_contents()->GetRenderViewHost()->GetView())
1092 if (guest_opaque_
) {
1094 ->GetRenderViewHost()
1096 ->SetBackgroundColorToDefault();
1098 web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor(
1099 SK_ColorTRANSPARENT
);
1103 void WebViewGuest::SetAllowScaling(bool allow
) {
1104 allow_scaling_
= allow
;
1107 bool WebViewGuest::LoadDataWithBaseURL(const std::string
& data_url
,
1108 const std::string
& base_url
,
1109 const std::string
& virtual_url
,
1110 std::string
* error
) {
1111 // Make GURLs from URLs.
1112 const GURL data_gurl
= GURL(data_url
);
1113 const GURL base_gurl
= GURL(base_url
);
1114 const GURL virtual_gurl
= GURL(virtual_url
);
1116 // Check that the provided URLs are valid.
1117 // |data_url| must be a valid data URL.
1118 if (!data_gurl
.is_valid() || !data_gurl
.SchemeIs(url::kDataScheme
)) {
1119 base::SStringPrintf(
1120 error
, webview::kAPILoadDataInvalidDataURL
, data_url
.c_str());
1123 // |base_url| must be a valid URL.
1124 if (!base_gurl
.is_valid()) {
1125 base::SStringPrintf(
1126 error
, webview::kAPILoadDataInvalidBaseURL
, base_url
.c_str());
1129 // |virtual_url| must be a valid URL.
1130 if (!virtual_gurl
.is_valid()) {
1131 base::SStringPrintf(
1132 error
, webview::kAPILoadDataInvalidVirtualURL
, virtual_url
.c_str());
1136 // Set up the parameters to load |data_url| with the specified |base_url|.
1137 content::NavigationController::LoadURLParams
load_params(data_gurl
);
1138 load_params
.load_type
= content::NavigationController::LOAD_TYPE_DATA
;
1139 load_params
.base_url_for_data_url
= base_gurl
;
1140 load_params
.virtual_url_for_data_url
= virtual_gurl
;
1141 load_params
.override_user_agent
=
1142 content::NavigationController::UA_OVERRIDE_INHERIT
;
1144 // Navigate to the data URL.
1145 GuestViewBase::LoadURLWithParams(load_params
);
1150 void WebViewGuest::AddNewContents(content::WebContents
* source
,
1151 content::WebContents
* new_contents
,
1152 WindowOpenDisposition disposition
,
1153 const gfx::Rect
& initial_rect
,
1155 bool* was_blocked
) {
1157 *was_blocked
= false;
1158 RequestNewWindowPermission(disposition
,
1164 content::WebContents
* WebViewGuest::OpenURLFromTab(
1165 content::WebContents
* source
,
1166 const content::OpenURLParams
& params
) {
1167 // There are two use cases to consider from a security perspective:
1168 // 1.) Renderer-initiated navigation to chrome:// must always be blocked even
1169 // if the <webview> is in WebUI. This is handled by
1170 // WebViewGuest::LoadURLWithParams. WebViewGuest::NavigateGuest will also
1171 // call LoadURLWithParams. CreateNewGuestWebViewWindow creates a new
1172 // WebViewGuest which will call NavigateGuest in DidInitialize.
1173 // 2.) The Language Settings context menu item should always work, both in
1174 // Chrome Apps and WebUI. This is a browser initiated request and so
1175 // we pass it along to the embedder's WebContentsDelegate to get the
1176 // browser to perform the action for the <webview>.
1177 if (!params
.is_renderer_initiated
) {
1178 if (!owner_web_contents()->GetDelegate())
1180 return owner_web_contents()->GetDelegate()->OpenURLFromTab(
1181 owner_web_contents(), params
);
1184 // If the guest wishes to navigate away prior to attachment then we save the
1185 // navigation to perform upon attachment. Navigation initializes a lot of
1186 // state that assumes an embedder exists, such as RenderWidgetHostViewGuest.
1187 // Navigation also resumes resource loading which we don't want to allow
1188 // until attachment.
1190 WebViewGuest
* opener
= GetOpener();
1191 auto it
= opener
->pending_new_windows_
.find(this);
1192 if (it
== opener
->pending_new_windows_
.end())
1194 const NewWindowInfo
& info
= it
->second
;
1195 NewWindowInfo
new_window_info(params
.url
, info
.name
);
1196 new_window_info
.changed
= new_window_info
.url
!= info
.url
;
1197 it
->second
= new_window_info
;
1201 // This code path is taken if RenderFrameImpl::DecidePolicyForNavigation
1202 // decides that a fork should happen. At the time of writing this comment,
1203 // the only way a well behaving guest could hit this code path is if it
1204 // navigates to a URL that's associated with the default search engine.
1205 // This list of URLs is generated by chrome::GetSearchURLs. Validity checks
1206 // are performed inside LoadURLWithParams such that if the guest attempts
1207 // to navigate to a URL that it is not allowed to navigate to, a 'loadabort'
1208 // event will fire in the embedder, and the guest will be navigated to
1210 if (params
.disposition
== CURRENT_TAB
) {
1211 LoadURLWithParams(params
.url
, params
.referrer
, params
.transition
,
1212 true /* force_navigation */);
1213 return web_contents();
1216 // This code path is taken if Ctrl+Click, middle click or any of the
1217 // keyboard/mouse combinations are used to open a link in a new tab/window.
1218 // This code path is also taken on client-side redirects from about:blank.
1219 CreateNewGuestWebViewWindow(params
);
1223 void WebViewGuest::WebContentsCreated(WebContents
* source_contents
,
1224 int opener_render_frame_id
,
1225 const base::string16
& frame_name
,
1226 const GURL
& target_url
,
1227 content::WebContents
* new_contents
) {
1228 auto guest
= WebViewGuest::FromWebContents(new_contents
);
1230 guest
->SetOpener(this);
1231 std::string guest_name
= base::UTF16ToUTF8(frame_name
);
1232 guest
->name_
= guest_name
;
1233 pending_new_windows_
.insert(
1234 std::make_pair(guest
, NewWindowInfo(target_url
, guest_name
)));
1237 void WebViewGuest::EnterFullscreenModeForTab(content::WebContents
* web_contents
,
1238 const GURL
& origin
) {
1239 // Ask the embedder for permission.
1240 base::DictionaryValue request_info
;
1241 request_info
.SetString(webview::kOrigin
, origin
.spec());
1242 web_view_permission_helper_
->RequestPermission(
1243 WEB_VIEW_PERMISSION_TYPE_FULLSCREEN
, request_info
,
1244 base::Bind(&WebViewGuest::OnFullscreenPermissionDecided
,
1245 weak_ptr_factory_
.GetWeakPtr()),
1246 false /* allowed_by_default */);
1248 // TODO(lazyboy): Right now the guest immediately goes fullscreen within its
1249 // bounds. If the embedder denies the permission then we will see a flicker.
1250 // Once we have the ability to "cancel" a renderer/ fullscreen request:
1251 // http://crbug.com/466854 this won't be necessary and we should be
1252 // Calling SetFullscreenState(true) once the embedder allowed the request.
1253 // Otherwise we would cancel renderer/ fullscreen if the embedder denied.
1254 SetFullscreenState(true);
1257 void WebViewGuest::ExitFullscreenModeForTab(
1258 content::WebContents
* web_contents
) {
1259 SetFullscreenState(false);
1262 bool WebViewGuest::IsFullscreenForTabOrPending(
1263 const content::WebContents
* web_contents
) const {
1264 return is_guest_fullscreen_
;
1267 void WebViewGuest::LoadURLWithParams(const GURL
& url
,
1268 const content::Referrer
& referrer
,
1269 ui::PageTransition transition_type
,
1270 bool force_navigation
) {
1271 // Do not allow navigating a guest to schemes other than known safe schemes.
1272 // This will block the embedder trying to load unwanted schemes, e.g.
1274 bool scheme_is_blocked
=
1275 (!content::ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
1277 !url
.SchemeIs(url::kAboutScheme
)) ||
1278 url
.SchemeIs(url::kJavaScriptScheme
);
1279 if (scheme_is_blocked
|| !url
.is_valid()) {
1280 LoadAbort(true /* is_top_level */, url
,
1281 net::ErrorToShortString(net::ERR_ABORTED
));
1282 NavigateGuest(url::kAboutBlankURL
, true /* force_navigation */);
1286 if (!force_navigation
&& (src_
== url
))
1289 GURL
validated_url(url
);
1290 web_contents()->GetRenderProcessHost()->FilterURL(false, &validated_url
);
1291 // As guests do not swap processes on navigation, only navigations to
1292 // normal web URLs are supported. No protocol handlers are installed for
1293 // other schemes (e.g., WebUI or extensions), and no permissions or bindings
1294 // can be granted to the guest process.
1295 content::NavigationController::LoadURLParams
load_url_params(validated_url
);
1296 load_url_params
.referrer
= referrer
;
1297 load_url_params
.transition_type
= transition_type
;
1298 load_url_params
.extra_headers
= std::string();
1299 if (is_overriding_user_agent_
) {
1300 load_url_params
.override_user_agent
=
1301 content::NavigationController::UA_OVERRIDE_TRUE
;
1303 GuestViewBase::LoadURLWithParams(load_url_params
);
1305 src_
= validated_url
;
1308 void WebViewGuest::RequestNewWindowPermission(
1309 WindowOpenDisposition disposition
,
1310 const gfx::Rect
& initial_bounds
,
1312 content::WebContents
* new_contents
) {
1313 auto guest
= WebViewGuest::FromWebContents(new_contents
);
1316 auto it
= pending_new_windows_
.find(guest
);
1317 if (it
== pending_new_windows_
.end())
1319 const NewWindowInfo
& new_window_info
= it
->second
;
1321 // Retrieve the opener partition info if we have it.
1322 const GURL
& site_url
= new_contents
->GetSiteInstance()->GetSiteURL();
1323 std::string storage_partition_id
= GetStoragePartitionIdFromSiteURL(site_url
);
1325 base::DictionaryValue request_info
;
1326 request_info
.SetInteger(webview::kInitialHeight
, initial_bounds
.height());
1327 request_info
.SetInteger(webview::kInitialWidth
, initial_bounds
.width());
1328 request_info
.Set(webview::kTargetURL
,
1329 new base::StringValue(new_window_info
.url
.spec()));
1330 request_info
.Set(webview::kName
, new base::StringValue(new_window_info
.name
));
1331 request_info
.SetInteger(webview::kWindowID
, guest
->guest_instance_id());
1332 // We pass in partition info so that window-s created through newwindow
1333 // API can use it to set their partition attribute.
1334 request_info
.Set(webview::kStoragePartitionId
,
1335 new base::StringValue(storage_partition_id
));
1337 webview::kWindowOpenDisposition
,
1338 new base::StringValue(WindowOpenDispositionToString(disposition
)));
1340 web_view_permission_helper_
->
1341 RequestPermission(WEB_VIEW_PERMISSION_TYPE_NEW_WINDOW
,
1343 base::Bind(&WebViewGuest::OnWebViewNewWindowResponse
,
1344 weak_ptr_factory_
.GetWeakPtr(),
1345 guest
->guest_instance_id()),
1346 false /* allowed_by_default */);
1349 GURL
WebViewGuest::ResolveURL(const std::string
& src
) {
1350 if (!in_extension())
1353 GURL
default_url(base::StringPrintf("%s://%s/",
1355 owner_extension_id().c_str()));
1356 return default_url
.Resolve(src
);
1359 void WebViewGuest::OnWebViewNewWindowResponse(
1360 int new_window_instance_id
,
1362 const std::string
& user_input
) {
1364 WebViewGuest::From(owner_web_contents()->GetRenderProcessHost()->GetID(),
1365 new_window_instance_id
);
1373 void WebViewGuest::OnFullscreenPermissionDecided(
1375 const std::string
& user_input
) {
1376 last_fullscreen_permission_was_allowed_by_embedder_
= allowed
;
1377 SetFullscreenState(allowed
);
1380 bool WebViewGuest::GuestMadeEmbedderFullscreen() const {
1381 return last_fullscreen_permission_was_allowed_by_embedder_
&&
1382 is_embedder_fullscreen_
;
1385 void WebViewGuest::SetFullscreenState(bool is_fullscreen
) {
1386 if (is_fullscreen
== is_guest_fullscreen_
)
1389 bool was_fullscreen
= is_guest_fullscreen_
;
1390 is_guest_fullscreen_
= is_fullscreen
;
1391 // If the embedder entered fullscreen because of us, it should exit fullscreen
1392 // when we exit fullscreen.
1393 if (was_fullscreen
&& GuestMadeEmbedderFullscreen()) {
1394 // Dispatch a message so we can call document.webkitCancelFullscreen()
1396 scoped_ptr
<base::DictionaryValue
> args(new base::DictionaryValue());
1397 DispatchEventToView(
1398 new GuestViewBase::Event(webview::kEventExitFullscreen
, args
.Pass()));
1400 // Since we changed fullscreen state, sending a Resize message ensures that
1401 // renderer/ sees the change.
1402 web_contents()->GetRenderViewHost()->WasResized();
1405 } // namespace extensions