Index: extensions/browser/guest_view/web_view/web_view_guest.cc |
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc |
index f4d1cc4fe7039f12593f52c921a9ad37c2f7acb5..c3bb661d6e8663cdd31685b641057f334e735a7b 100644 |
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc |
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc |
@@ -201,6 +201,25 @@ static base::LazyInstance<WebViewKeyToIDMap> web_view_key_to_id_map = |
} // namespace |
+WebViewGuest::WebViewGuest(WebContents* owner_web_contents) |
+ : GuestView<WebViewGuest>(owner_web_contents), |
+ rules_registry_id_(RulesRegistryService::kInvalidRulesRegistryID), |
+ find_helper_(this), |
+ is_overriding_user_agent_(false), |
+ allow_transparency_(false), |
+ javascript_dialog_helper_(this), |
+ allow_scaling_(false), |
+ is_guest_fullscreen_(false), |
+ is_embedder_fullscreen_(false), |
+ last_fullscreen_permission_was_allowed_by_embedder_(false), |
+ pending_zoom_factor_(0.0), |
+ weak_ptr_factory_(this) { |
+ web_view_guest_delegate_.reset( |
+ ExtensionsAPIClient::Get()->CreateWebViewGuestDelegate(this)); |
+} |
+ |
+WebViewGuest::~WebViewGuest() {} |
+ |
// static |
void WebViewGuest::CleanUp(content::BrowserContext* browser_context, |
int embedder_process_id, |
@@ -303,155 +322,75 @@ int WebViewGuest::GetOrGenerateRulesRegistryID( |
return rules_registry_id; |
} |
-bool WebViewGuest::CanRunInDetachedState() const { |
- return true; |
-} |
- |
-void WebViewGuest::CreateWebContents( |
- const base::DictionaryValue& create_params, |
- const WebContentsCreatedCallback& callback) { |
- RenderProcessHost* owner_render_process_host = |
- owner_web_contents()->GetRenderProcessHost(); |
- std::string storage_partition_id; |
- bool persist_storage = false; |
- ParsePartitionParam(create_params, &storage_partition_id, &persist_storage); |
- // Validate that the partition id coming from the renderer is valid UTF-8, |
- // since we depend on this in other parts of the code, such as FilePath |
- // creation. If the validation fails, treat it as a bad message and kill the |
- // renderer process. |
- if (!base::IsStringUTF8(storage_partition_id)) { |
- content::RecordAction( |
- base::UserMetricsAction("BadMessageTerminate_BPGM")); |
- owner_render_process_host->Shutdown(content::RESULT_CODE_KILLED_BAD_MESSAGE, |
- false); |
- callback.Run(nullptr); |
- return; |
- } |
- std::string url_encoded_partition = net::EscapeQueryParamValue( |
- storage_partition_id, false); |
- std::string partition_domain = GetOwnerSiteURL().host(); |
- GURL guest_site(base::StringPrintf("%s://%s/%s?%s", |
- content::kGuestScheme, |
- partition_domain.c_str(), |
- persist_storage ? "persist" : "", |
- url_encoded_partition.c_str())); |
- |
- // If we already have a webview tag in the same app using the same storage |
- // partition, we should use the same SiteInstance so the existing tag and |
- // the new tag can script each other. |
- auto guest_view_manager = GuestViewManager::FromBrowserContext( |
- owner_render_process_host->GetBrowserContext()); |
- content::SiteInstance* guest_site_instance = |
- guest_view_manager->GetGuestSiteInstance(guest_site); |
- if (!guest_site_instance) { |
- // Create the SiteInstance in a new BrowsingInstance, which will ensure |
- // that webview tags are also not allowed to send messages across |
- // different partitions. |
- guest_site_instance = content::SiteInstance::CreateForURL( |
- owner_render_process_host->GetBrowserContext(), guest_site); |
- } |
- WebContents::CreateParams params( |
- owner_render_process_host->GetBrowserContext(), |
- guest_site_instance); |
- params.guest_delegate = this; |
- callback.Run(WebContents::Create(params)); |
-} |
- |
-void WebViewGuest::DidAttachToEmbedder() { |
- ApplyAttributes(*attach_params()); |
+double WebViewGuest::GetZoom() const { |
+ double zoom_level = |
+ ZoomController::FromWebContents(web_contents())->GetZoomLevel(); |
+ return ConvertZoomLevelToZoomFactor(zoom_level); |
} |
-void WebViewGuest::DidDropLink(const GURL& url) { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetString(guest_view::kUrl, url.spec()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventDropLink, args.Pass())); |
+ZoomController::ZoomMode WebViewGuest::GetZoomMode() { |
+ return ZoomController::FromWebContents(web_contents())->zoom_mode(); |
} |
-void WebViewGuest::DidInitialize(const base::DictionaryValue& create_params) { |
- script_executor_.reset( |
- new ScriptExecutor(web_contents(), &script_observers_)); |
+void WebViewGuest::NavigateGuest(const std::string& src, |
+ bool force_navigation) { |
+ if (src.empty()) |
+ return; |
- notification_registrar_.Add(this, |
- content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, |
- content::Source<WebContents>(web_contents())); |
+ GURL url = ResolveURL(src); |
- notification_registrar_.Add(this, |
- content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, |
- content::Source<WebContents>(web_contents())); |
+ // We wait for all the content scripts to load and then navigate the guest |
+ // if the navigation is embedder-initiated. For browser-initiated navigations, |
+ // content scripts will be ready. |
+ if (force_navigation) { |
+ SignalWhenReady(base::Bind( |
+ &WebViewGuest::LoadURLWithParams, weak_ptr_factory_.GetWeakPtr(), url, |
+ content::Referrer(), ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
+ GlobalRequestID(), force_navigation)); |
+ return; |
+ } |
+ LoadURLWithParams(url, content::Referrer(), ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
+ GlobalRequestID(), force_navigation); |
+} |
+void WebViewGuest::ShowContextMenu( |
+ int request_id, |
+ const WebViewGuestDelegate::MenuItemVector* items) { |
if (web_view_guest_delegate_) |
- web_view_guest_delegate_->OnDidInitialize(); |
- ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents()); |
- web_view_permission_helper_.reset(new WebViewPermissionHelper(this)); |
- |
- rules_registry_id_ = GetOrGenerateRulesRegistryID( |
- owner_web_contents()->GetRenderProcessHost()->GetID(), |
- view_instance_id()); |
- |
- // We must install the mapping from guests to WebViews prior to resuming |
- // suspended resource loads so that the WebRequest API will catch resource |
- // requests. |
- PushWebViewStateToIOThread(); |
- |
- ApplyAttributes(create_params); |
+ web_view_guest_delegate_->OnShowContextMenu(request_id, items); |
} |
-void WebViewGuest::ClearDataInternal(base::Time remove_since, |
- uint32 removal_mask, |
- const base::Closure& callback) { |
- uint32 storage_partition_removal_mask = |
- GetStoragePartitionRemovalMask(removal_mask); |
- if (!storage_partition_removal_mask) { |
- callback.Run(); |
+void WebViewGuest::SetName(const std::string& name) { |
+ if (name_ == name) |
return; |
- } |
- content::StoragePartition* partition = |
- content::BrowserContext::GetStoragePartition( |
- web_contents()->GetBrowserContext(), |
- web_contents()->GetSiteInstance()); |
- partition->ClearData( |
- storage_partition_removal_mask, |
- content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, GURL(), |
- content::StoragePartition::OriginMatcherFunction(), remove_since, |
- base::Time::Now(), callback); |
-} |
+ name_ = name; |
-void WebViewGuest::GuestViewDidStopLoading() { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventLoadStop, args.Pass())); |
+ Send(new ExtensionMsg_SetFrameName(routing_id(), name_)); |
} |
-void WebViewGuest::EmbedderFullscreenToggled(bool entered_fullscreen) { |
- is_embedder_fullscreen_ = entered_fullscreen; |
- // If the embedder has got out of fullscreen, we get out of fullscreen |
- // mode as well. |
- if (!entered_fullscreen) |
- SetFullscreenState(false); |
+void WebViewGuest::SetZoom(double zoom_factor) { |
+ auto zoom_controller = ZoomController::FromWebContents(web_contents()); |
+ DCHECK(zoom_controller); |
+ double zoom_level = content::ZoomFactorToZoomLevel(zoom_factor); |
+ zoom_controller->SetZoomLevel(zoom_level); |
} |
-const char* WebViewGuest::GetAPINamespace() const { |
- return webview::kAPINamespace; |
+void WebViewGuest::SetZoomMode(ZoomController::ZoomMode zoom_mode) { |
+ ZoomController::FromWebContents(web_contents())->SetZoomMode(zoom_mode); |
} |
-int WebViewGuest::GetTaskPrefix() const { |
- return IDS_EXTENSION_TASK_MANAGER_WEBVIEW_TAG_PREFIX; |
+void WebViewGuest::SetAllowScaling(bool allow) { |
+ allow_scaling_ = allow; |
} |
-void WebViewGuest::GuestDestroyed() { |
- RemoveWebViewStateFromIOThread(web_contents()); |
-} |
+void WebViewGuest::SetAllowTransparency(bool allow) { |
+ if (allow_transparency_ == allow) |
+ return; |
-void WebViewGuest::GuestReady() { |
- // The guest RenderView should always live in an isolated guest process. |
- CHECK(web_contents()->GetRenderProcessHost()->IsForGuestsOnly()); |
- Send(new ExtensionMsg_SetFrameName(web_contents()->GetRoutingID(), name_)); |
+ allow_transparency_ = allow; |
+ if (!web_contents()->GetRenderViewHost()->GetView()) |
+ return; |
- // We don't want to accidentally set the opacity of an interstitial page. |
- // WebContents::GetRenderWidgetHostView will return the RWHV of an |
- // interstitial page if one is showing at this time. We only want opacity |
- // to apply to web pages. |
if (allow_transparency_) { |
web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor( |
SK_ColorTRANSPARENT); |
@@ -463,221 +402,59 @@ void WebViewGuest::GuestReady() { |
} |
} |
-void WebViewGuest::GuestSizeChangedDueToAutoSize(const gfx::Size& old_size, |
- const gfx::Size& new_size) { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetInteger(webview::kOldHeight, old_size.height()); |
- args->SetInteger(webview::kOldWidth, old_size.width()); |
- args->SetInteger(webview::kNewHeight, new_size.height()); |
- args->SetInteger(webview::kNewWidth, new_size.width()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventSizeChanged, args.Pass())); |
-} |
+bool WebViewGuest::LoadDataWithBaseURL(const std::string& data_url, |
+ const std::string& base_url, |
+ const std::string& virtual_url, |
+ std::string* error) { |
+ // Make GURLs from URLs. |
+ const GURL data_gurl = GURL(data_url); |
+ const GURL base_gurl = GURL(base_url); |
+ const GURL virtual_gurl = GURL(virtual_url); |
+ |
+ // Check that the provided URLs are valid. |
+ // |data_url| must be a valid data URL. |
+ if (!data_gurl.is_valid() || !data_gurl.SchemeIs(url::kDataScheme)) { |
+ base::SStringPrintf(error, webview::kAPILoadDataInvalidDataURL, |
+ data_url.c_str()); |
+ return false; |
+ } |
+ // |base_url| must be a valid URL. |
+ if (!base_gurl.is_valid()) { |
+ base::SStringPrintf(error, webview::kAPILoadDataInvalidBaseURL, |
+ base_url.c_str()); |
+ return false; |
+ } |
+ // |virtual_url| must be a valid URL. |
+ if (!virtual_gurl.is_valid()) { |
+ base::SStringPrintf(error, webview::kAPILoadDataInvalidVirtualURL, |
+ virtual_url.c_str()); |
+ return false; |
+ } |
+ |
+ // Set up the parameters to load |data_url| with the specified |base_url|. |
+ content::NavigationController::LoadURLParams load_params(data_gurl); |
+ load_params.load_type = content::NavigationController::LOAD_TYPE_DATA; |
+ load_params.base_url_for_data_url = base_gurl; |
+ load_params.virtual_url_for_data_url = virtual_gurl; |
+ load_params.override_user_agent = |
+ content::NavigationController::UA_OVERRIDE_INHERIT; |
+ |
+ // Navigate to the data URL. |
+ GuestViewBase::LoadURLWithParams(load_params); |
-bool WebViewGuest::IsAutoSizeSupported() const { |
return true; |
} |
-void WebViewGuest::GuestZoomChanged(double old_zoom_level, |
- double new_zoom_level) { |
- // Dispatch the zoomchange event. |
- double old_zoom_factor = ConvertZoomLevelToZoomFactor(old_zoom_level); |
- double new_zoom_factor = ConvertZoomLevelToZoomFactor(new_zoom_level); |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetDouble(webview::kOldZoomFactor, old_zoom_factor); |
- args->SetDouble(webview::kNewZoomFactor, new_zoom_factor); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventZoomChange, args.Pass())); |
+void WebViewGuest::StartFindInternal( |
+ const base::string16& search_text, |
+ const blink::WebFindOptions& options, |
+ scoped_refptr<WebViewInternalFindFunction> find_function) { |
+ find_helper_.Find(web_contents(), search_text, options, find_function); |
} |
-void WebViewGuest::WillDestroy() { |
- if (!attached() && GetOpener()) |
- GetOpener()->pending_new_windows_.erase(this); |
-} |
- |
-bool WebViewGuest::AddMessageToConsole(WebContents* source, |
- int32 level, |
- const base::string16& message, |
- int32 line_no, |
- const base::string16& source_id) { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- // Log levels are from base/logging.h: LogSeverity. |
- args->SetInteger(webview::kLevel, level); |
- args->SetString(webview::kMessage, message); |
- args->SetInteger(webview::kLine, line_no); |
- args->SetString(webview::kSourceId, source_id); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventConsoleMessage, args.Pass())); |
- return true; |
-} |
- |
-void WebViewGuest::CloseContents(WebContents* source) { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventClose, args.Pass())); |
-} |
- |
-void WebViewGuest::FindReply(WebContents* source, |
- int request_id, |
- int number_of_matches, |
- const gfx::Rect& selection_rect, |
- int active_match_ordinal, |
- bool final_update) { |
- GuestViewBase::FindReply(source, request_id, number_of_matches, |
- selection_rect, active_match_ordinal, final_update); |
- find_helper_.FindReply(request_id, number_of_matches, selection_rect, |
- active_match_ordinal, final_update); |
-} |
- |
-double WebViewGuest::GetZoom() const { |
- double zoom_level = |
- ZoomController::FromWebContents(web_contents())->GetZoomLevel(); |
- return ConvertZoomLevelToZoomFactor(zoom_level); |
-} |
- |
-ZoomController::ZoomMode WebViewGuest::GetZoomMode() { |
- return ZoomController::FromWebContents(web_contents())->zoom_mode(); |
-} |
- |
-bool WebViewGuest::HandleContextMenu( |
- const content::ContextMenuParams& params) { |
- if (!web_view_guest_delegate_) |
- return false; |
- return web_view_guest_delegate_->HandleContextMenu(params); |
-} |
- |
-void WebViewGuest::HandleKeyboardEvent( |
- WebContents* source, |
- const content::NativeWebKeyboardEvent& event) { |
- if (HandleKeyboardShortcuts(event)) |
- return; |
- |
- GuestViewBase::HandleKeyboardEvent(source, event); |
-} |
- |
-bool WebViewGuest::PreHandleGestureEvent(WebContents* source, |
- const blink::WebGestureEvent& event) { |
- return !allow_scaling_ && GuestViewBase::PreHandleGestureEvent(source, event); |
-} |
- |
-void WebViewGuest::LoadProgressChanged(WebContents* source, double progress) { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetString(guest_view::kUrl, web_contents()->GetURL().spec()); |
- args->SetDouble(webview::kProgress, progress); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventLoadProgress, args.Pass())); |
-} |
- |
-void WebViewGuest::LoadAbort(bool is_top_level, |
- const GURL& url, |
- int error_code, |
- const std::string& error_type) { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetBoolean(guest_view::kIsTopLevel, is_top_level); |
- args->SetString(guest_view::kUrl, url.possibly_invalid_spec()); |
- args->SetInteger(guest_view::kCode, error_code); |
- args->SetString(guest_view::kReason, error_type); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventLoadAbort, args.Pass())); |
-} |
- |
-void WebViewGuest::SetContextMenuPosition(const gfx::Point& position) { |
- if (web_view_guest_delegate_) |
- web_view_guest_delegate_->SetContextMenuPosition(position); |
-} |
- |
-void WebViewGuest::CreateNewGuestWebViewWindow( |
- const content::OpenURLParams& params) { |
- GuestViewManager* guest_manager = |
- GuestViewManager::FromBrowserContext(browser_context()); |
- // Set the attach params to use the same partition as the opener. |
- // We pull the partition information from the site's URL, which is of the |
- // form guest://site/{persist}?{partition_name}. |
- const GURL& site_url = web_contents()->GetSiteInstance()->GetSiteURL(); |
- const std::string storage_partition_id = |
- GetStoragePartitionIdFromSiteURL(site_url); |
- base::DictionaryValue create_params; |
- create_params.SetString(webview::kStoragePartitionId, storage_partition_id); |
- |
- guest_manager->CreateGuest(WebViewGuest::Type, |
- embedder_web_contents(), |
- create_params, |
- base::Bind(&WebViewGuest::NewGuestWebViewCallback, |
- weak_ptr_factory_.GetWeakPtr(), |
- params)); |
-} |
- |
-void WebViewGuest::NewGuestWebViewCallback(const content::OpenURLParams& params, |
- WebContents* guest_web_contents) { |
- WebViewGuest* new_guest = WebViewGuest::FromWebContents(guest_web_contents); |
- new_guest->SetOpener(this); |
- |
- // Take ownership of |new_guest|. |
- pending_new_windows_.insert( |
- std::make_pair(new_guest, NewWindowInfo(params.url, std::string()))); |
- |
- // Request permission to show the new window. |
- RequestNewWindowPermission(params.disposition, |
- gfx::Rect(), |
- params.user_gesture, |
- new_guest->web_contents()); |
-} |
- |
-// TODO(fsamuel): Find a reliable way to test the 'responsive' and |
-// 'unresponsive' events. |
-void WebViewGuest::RendererResponsive(WebContents* source) { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetInteger(webview::kProcessId, |
- web_contents()->GetRenderProcessHost()->GetID()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventResponsive, args.Pass())); |
-} |
- |
-void WebViewGuest::RendererUnresponsive(WebContents* source) { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetInteger(webview::kProcessId, |
- web_contents()->GetRenderProcessHost()->GetID()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventUnresponsive, args.Pass())); |
-} |
- |
-void WebViewGuest::Observe(int type, |
- const content::NotificationSource& source, |
- const content::NotificationDetails& details) { |
- switch (type) { |
- case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: { |
- DCHECK_EQ(content::Source<WebContents>(source).ptr(), web_contents()); |
- if (content::Source<WebContents>(source).ptr() == web_contents()) |
- LoadHandlerCalled(); |
- break; |
- } |
- case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: { |
- DCHECK_EQ(content::Source<WebContents>(source).ptr(), web_contents()); |
- content::ResourceRedirectDetails* resource_redirect_details = |
- content::Details<content::ResourceRedirectDetails>(details).ptr(); |
- bool is_top_level = resource_redirect_details->resource_type == |
- content::RESOURCE_TYPE_MAIN_FRAME; |
- LoadRedirect(resource_redirect_details->url, |
- resource_redirect_details->new_url, |
- is_top_level); |
- break; |
- } |
- default: |
- NOTREACHED() << "Unexpected notification sent."; |
- break; |
- } |
-} |
- |
-void WebViewGuest::StartFindInternal( |
- const base::string16& search_text, |
- const blink::WebFindOptions& options, |
- scoped_refptr<WebViewInternalFindFunction> find_function) { |
- find_helper_.Find(web_contents(), search_text, options, find_function); |
-} |
- |
-void WebViewGuest::StopFindingInternal(content::StopFindAction action) { |
- find_helper_.CancelAllFindSessions(); |
- web_contents()->StopFinding(action); |
+void WebViewGuest::StopFindingInternal(content::StopFindAction action) { |
+ find_helper_.CancelAllFindSessions(); |
+ web_contents()->StopFinding(action); |
} |
bool WebViewGuest::Go(int relative_index) { |
@@ -756,221 +533,247 @@ bool WebViewGuest::ClearData(base::Time remove_since, |
return true; |
} |
-WebViewGuest::WebViewGuest(WebContents* owner_web_contents) |
- : GuestView<WebViewGuest>(owner_web_contents), |
- rules_registry_id_(RulesRegistryService::kInvalidRulesRegistryID), |
- find_helper_(this), |
- is_overriding_user_agent_(false), |
- allow_transparency_(false), |
- javascript_dialog_helper_(this), |
- allow_scaling_(false), |
- is_guest_fullscreen_(false), |
- is_embedder_fullscreen_(false), |
- last_fullscreen_permission_was_allowed_by_embedder_(false), |
- pending_zoom_factor_(0.0), |
- weak_ptr_factory_(this) { |
- web_view_guest_delegate_.reset( |
- ExtensionsAPIClient::Get()->CreateWebViewGuestDelegate(this)); |
-} |
- |
-WebViewGuest::~WebViewGuest() { |
-} |
- |
-void WebViewGuest::DidCommitProvisionalLoadForFrame( |
- content::RenderFrameHost* render_frame_host, |
- const GURL& url, |
- ui::PageTransition transition_type) { |
- if (!render_frame_host->GetParent()) { |
- src_ = url; |
- // Handle a pending zoom if one exists. |
- if (pending_zoom_factor_) { |
- SetZoom(pending_zoom_factor_); |
- pending_zoom_factor_ = 0.0; |
- } |
+void WebViewGuest::ClearDataInternal(base::Time remove_since, |
+ uint32 removal_mask, |
+ const base::Closure& callback) { |
+ uint32 storage_partition_removal_mask = |
+ GetStoragePartitionRemovalMask(removal_mask); |
+ if (!storage_partition_removal_mask) { |
+ callback.Run(); |
+ return; |
} |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetString(guest_view::kUrl, url.spec()); |
- args->SetBoolean(guest_view::kIsTopLevel, !render_frame_host->GetParent()); |
- args->SetString(webview::kInternalBaseURLForDataURL, |
- web_contents() |
- ->GetController() |
- .GetLastCommittedEntry() |
- ->GetBaseURLForDataURL() |
- .spec()); |
- args->SetInteger(webview::kInternalCurrentEntryIndex, |
- web_contents()->GetController().GetCurrentEntryIndex()); |
- args->SetInteger(webview::kInternalEntryCount, |
- web_contents()->GetController().GetEntryCount()); |
- args->SetInteger(webview::kInternalProcessId, |
- web_contents()->GetRenderProcessHost()->GetID()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventLoadCommit, args.Pass())); |
- |
- find_helper_.CancelAllFindSessions(); |
+ content::StoragePartition* partition = |
+ content::BrowserContext::GetStoragePartition( |
+ web_contents()->GetBrowserContext(), |
+ web_contents()->GetSiteInstance()); |
+ partition->ClearData( |
+ storage_partition_removal_mask, |
+ content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, GURL(), |
+ content::StoragePartition::OriginMatcherFunction(), remove_since, |
+ base::Time::Now(), callback); |
} |
-void WebViewGuest::DidFailProvisionalLoad( |
- content::RenderFrameHost* render_frame_host, |
- const GURL& validated_url, |
- int error_code, |
- const base::string16& error_description, |
- bool was_ignored_by_handler) { |
- // Suppress loadabort for "mailto" URLs. |
- if (validated_url.SchemeIs(url::kMailToScheme)) |
+void WebViewGuest::OnWebViewNewWindowResponse(int new_window_instance_id, |
+ bool allow, |
+ const std::string& user_input) { |
+ auto guest = |
+ WebViewGuest::From(owner_web_contents()->GetRenderProcessHost()->GetID(), |
+ new_window_instance_id); |
+ if (!guest) |
return; |
- LoadAbort(!render_frame_host->GetParent(), validated_url, error_code, |
- net::ErrorToShortString(error_code)); |
+ if (!allow) |
+ guest->Destroy(); |
} |
-void WebViewGuest::DidStartProvisionalLoadForFrame( |
- content::RenderFrameHost* render_frame_host, |
- const GURL& validated_url, |
- bool is_error_page, |
- bool is_iframe_srcdoc) { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetString(guest_view::kUrl, validated_url.spec()); |
- args->SetBoolean(guest_view::kIsTopLevel, !render_frame_host->GetParent()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventLoadStart, args.Pass())); |
+void WebViewGuest::OnFullscreenPermissionDecided( |
+ bool allowed, |
+ const std::string& user_input) { |
+ last_fullscreen_permission_was_allowed_by_embedder_ = allowed; |
+ SetFullscreenState(allowed); |
} |
-void WebViewGuest::RenderProcessGone(base::TerminationStatus status) { |
- // Cancel all find sessions in progress. |
- find_helper_.CancelAllFindSessions(); |
- |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetInteger(webview::kProcessId, |
- web_contents()->GetRenderProcessHost()->GetID()); |
- args->SetString(webview::kReason, TerminationStatusToString(status)); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventExit, args.Pass())); |
+bool WebViewGuest::GuestMadeEmbedderFullscreen() const { |
+ return last_fullscreen_permission_was_allowed_by_embedder_ && |
+ is_embedder_fullscreen_; |
} |
-void WebViewGuest::UserAgentOverrideSet(const std::string& user_agent) { |
- content::NavigationController& controller = web_contents()->GetController(); |
- content::NavigationEntry* entry = controller.GetVisibleEntry(); |
- if (!entry) |
+void WebViewGuest::SetFullscreenState(bool is_fullscreen) { |
+ if (is_fullscreen == is_guest_fullscreen_) |
return; |
- entry->SetIsOverridingUserAgent(!user_agent.empty()); |
- web_contents()->GetController().Reload(false); |
+ |
+ bool was_fullscreen = is_guest_fullscreen_; |
+ is_guest_fullscreen_ = is_fullscreen; |
+ // If the embedder entered fullscreen because of us, it should exit fullscreen |
+ // when we exit fullscreen. |
+ if (was_fullscreen && GuestMadeEmbedderFullscreen()) { |
+ // Dispatch a message so we can call document.webkitCancelFullscreen() |
+ // on the embedder. |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventExitFullscreen, args.Pass())); |
+ } |
+ // Since we changed fullscreen state, sending a Resize message ensures that |
+ // renderer/ sees the change. |
+ web_contents()->GetRenderViewHost()->WasResized(); |
} |
-void WebViewGuest::FrameNameChanged(RenderFrameHost* render_frame_host, |
- const std::string& name) { |
- if (render_frame_host->GetParent()) |
- return; |
+bool WebViewGuest::CanRunInDetachedState() const { |
+ return true; |
+} |
- if (name_ == name) |
+void WebViewGuest::CreateWebContents( |
+ const base::DictionaryValue& create_params, |
+ const WebContentsCreatedCallback& callback) { |
+ RenderProcessHost* owner_render_process_host = |
+ owner_web_contents()->GetRenderProcessHost(); |
+ std::string storage_partition_id; |
+ bool persist_storage = false; |
+ ParsePartitionParam(create_params, &storage_partition_id, &persist_storage); |
+ // Validate that the partition id coming from the renderer is valid UTF-8, |
+ // since we depend on this in other parts of the code, such as FilePath |
+ // creation. If the validation fails, treat it as a bad message and kill the |
+ // renderer process. |
+ if (!base::IsStringUTF8(storage_partition_id)) { |
+ content::RecordAction(base::UserMetricsAction("BadMessageTerminate_BPGM")); |
+ owner_render_process_host->Shutdown(content::RESULT_CODE_KILLED_BAD_MESSAGE, |
+ false); |
+ callback.Run(nullptr); |
return; |
+ } |
+ std::string url_encoded_partition = |
+ net::EscapeQueryParamValue(storage_partition_id, false); |
+ std::string partition_domain = GetOwnerSiteURL().host(); |
+ GURL guest_site(base::StringPrintf( |
+ "%s://%s/%s?%s", content::kGuestScheme, partition_domain.c_str(), |
+ persist_storage ? "persist" : "", url_encoded_partition.c_str())); |
- ReportFrameNameChange(name); |
+ // If we already have a webview tag in the same app using the same storage |
+ // partition, we should use the same SiteInstance so the existing tag and |
+ // the new tag can script each other. |
+ auto guest_view_manager = GuestViewManager::FromBrowserContext( |
+ owner_render_process_host->GetBrowserContext()); |
+ content::SiteInstance* guest_site_instance = |
+ guest_view_manager->GetGuestSiteInstance(guest_site); |
+ if (!guest_site_instance) { |
+ // Create the SiteInstance in a new BrowsingInstance, which will ensure |
+ // that webview tags are also not allowed to send messages across |
+ // different partitions. |
+ guest_site_instance = content::SiteInstance::CreateForURL( |
+ owner_render_process_host->GetBrowserContext(), guest_site); |
+ } |
+ WebContents::CreateParams params( |
+ owner_render_process_host->GetBrowserContext(), guest_site_instance); |
+ params.guest_delegate = this; |
+ callback.Run(WebContents::Create(params)); |
} |
-void WebViewGuest::ReportFrameNameChange(const std::string& name) { |
- name_ = name; |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetString(webview::kName, name); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventFrameNameChanged, args.Pass())); |
+void WebViewGuest::DidAttachToEmbedder() { |
+ ApplyAttributes(*attach_params()); |
} |
-void WebViewGuest::LoadHandlerCalled() { |
+void WebViewGuest::DidDropLink(const GURL& url) { |
scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventContentLoad, args.Pass())); |
+ args->SetString(guest_view::kUrl, url.spec()); |
+ DispatchEventToView(new GuestViewEvent(webview::kEventDropLink, args.Pass())); |
} |
-void WebViewGuest::LoadRedirect(const GURL& old_url, |
- const GURL& new_url, |
- bool is_top_level) { |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- args->SetBoolean(guest_view::kIsTopLevel, is_top_level); |
- args->SetString(webview::kNewURL, new_url.spec()); |
- args->SetString(webview::kOldURL, old_url.spec()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventLoadRedirect, args.Pass())); |
+void WebViewGuest::DidInitialize(const base::DictionaryValue& create_params) { |
+ script_executor_.reset( |
+ new ScriptExecutor(web_contents(), &script_observers_)); |
+ |
+ notification_registrar_.Add(this, |
+ content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, |
+ content::Source<WebContents>(web_contents())); |
+ |
+ notification_registrar_.Add(this, |
+ content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, |
+ content::Source<WebContents>(web_contents())); |
+ |
+ if (web_view_guest_delegate_) |
+ web_view_guest_delegate_->OnDidInitialize(); |
+ ExtensionsAPIClient::Get()->AttachWebContentsHelpers(web_contents()); |
+ web_view_permission_helper_.reset(new WebViewPermissionHelper(this)); |
+ |
+ rules_registry_id_ = GetOrGenerateRulesRegistryID( |
+ owner_web_contents()->GetRenderProcessHost()->GetID(), |
+ view_instance_id()); |
+ |
+ // We must install the mapping from guests to WebViews prior to resuming |
+ // suspended resource loads so that the WebRequest API will catch resource |
+ // requests. |
+ PushWebViewStateToIOThread(); |
+ |
+ ApplyAttributes(create_params); |
} |
-void WebViewGuest::PushWebViewStateToIOThread() { |
- const GURL& site_url = web_contents()->GetSiteInstance()->GetSiteURL(); |
- std::string partition_domain; |
- std::string partition_id; |
- bool in_memory; |
- if (!GetGuestPartitionConfigForSite( |
- site_url, &partition_domain, &partition_id, &in_memory)) { |
- NOTREACHED(); |
- return; |
- } |
+void WebViewGuest::EmbedderFullscreenToggled(bool entered_fullscreen) { |
+ is_embedder_fullscreen_ = entered_fullscreen; |
+ // If the embedder has got out of fullscreen, we get out of fullscreen |
+ // mode as well. |
+ if (!entered_fullscreen) |
+ SetFullscreenState(false); |
+} |
- WebViewRendererState::WebViewInfo web_view_info; |
- web_view_info.embedder_process_id = |
- owner_web_contents()->GetRenderProcessHost()->GetID(); |
- web_view_info.instance_id = view_instance_id(); |
- web_view_info.partition_id = partition_id; |
- web_view_info.owner_host = owner_host(); |
- web_view_info.rules_registry_id = rules_registry_id_; |
+void WebViewGuest::FindReply(WebContents* source, |
+ int request_id, |
+ int number_of_matches, |
+ const gfx::Rect& selection_rect, |
+ int active_match_ordinal, |
+ bool final_update) { |
+ GuestViewBase::FindReply(source, request_id, number_of_matches, |
+ selection_rect, active_match_ordinal, final_update); |
+ find_helper_.FindReply(request_id, number_of_matches, selection_rect, |
+ active_match_ordinal, final_update); |
+} |
- // Get content scripts IDs added by the guest. |
- WebViewContentScriptManager* manager = |
- WebViewContentScriptManager::Get(browser_context()); |
- DCHECK(manager); |
- web_view_info.content_script_ids = manager->GetContentScriptIDSet( |
- web_view_info.embedder_process_id, web_view_info.instance_id); |
+const char* WebViewGuest::GetAPINamespace() const { |
+ return webview::kAPINamespace; |
+} |
- content::BrowserThread::PostTask( |
- content::BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&WebViewRendererState::AddGuest, |
- base::Unretained(WebViewRendererState::GetInstance()), |
- web_contents()->GetRenderProcessHost()->GetID(), |
- web_contents()->GetRoutingID(), |
- web_view_info)); |
+int WebViewGuest::GetTaskPrefix() const { |
+ return IDS_EXTENSION_TASK_MANAGER_WEBVIEW_TAG_PREFIX; |
} |
-// static |
-void WebViewGuest::RemoveWebViewStateFromIOThread( |
- WebContents* web_contents) { |
- content::BrowserThread::PostTask( |
- content::BrowserThread::IO, FROM_HERE, |
- base::Bind( |
- &WebViewRendererState::RemoveGuest, |
- base::Unretained(WebViewRendererState::GetInstance()), |
- web_contents->GetRenderProcessHost()->GetID(), |
- web_contents->GetRoutingID())); |
+void WebViewGuest::GuestDestroyed() { |
+ RemoveWebViewStateFromIOThread(web_contents()); |
} |
-void WebViewGuest::RequestMediaAccessPermission( |
- WebContents* source, |
- const content::MediaStreamRequest& request, |
- const content::MediaResponseCallback& callback) { |
- web_view_permission_helper_->RequestMediaAccessPermission(source, |
- request, |
- callback); |
+void WebViewGuest::GuestReady() { |
+ // The guest RenderView should always live in an isolated guest process. |
+ CHECK(web_contents()->GetRenderProcessHost()->IsForGuestsOnly()); |
+ Send(new ExtensionMsg_SetFrameName(web_contents()->GetRoutingID(), name_)); |
+ |
+ // We don't want to accidentally set the opacity of an interstitial page. |
+ // WebContents::GetRenderWidgetHostView will return the RWHV of an |
+ // interstitial page if one is showing at this time. We only want opacity |
+ // to apply to web pages. |
+ if (allow_transparency_) { |
+ web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor( |
+ SK_ColorTRANSPARENT); |
+ } else { |
+ web_contents() |
+ ->GetRenderViewHost() |
+ ->GetView() |
+ ->SetBackgroundColorToDefault(); |
+ } |
} |
-bool WebViewGuest::CheckMediaAccessPermission(WebContents* source, |
- const GURL& security_origin, |
- content::MediaStreamType type) { |
- return web_view_permission_helper_->CheckMediaAccessPermission( |
- source, security_origin, type); |
+void WebViewGuest::GuestSizeChangedDueToAutoSize(const gfx::Size& old_size, |
+ const gfx::Size& new_size) { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetInteger(webview::kOldHeight, old_size.height()); |
+ args->SetInteger(webview::kOldWidth, old_size.width()); |
+ args->SetInteger(webview::kNewHeight, new_size.height()); |
+ args->SetInteger(webview::kNewWidth, new_size.width()); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventSizeChanged, args.Pass())); |
} |
-void WebViewGuest::CanDownload( |
- const GURL& url, |
- const std::string& request_method, |
- const base::Callback<void(bool)>& callback) { |
- web_view_permission_helper_->CanDownload(url, request_method, callback); |
+void WebViewGuest::GuestViewDidStopLoading() { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ DispatchEventToView(new GuestViewEvent(webview::kEventLoadStop, args.Pass())); |
} |
-void WebViewGuest::RequestPointerLockPermission( |
- bool user_gesture, |
- bool last_unlocked_by_target, |
- const base::Callback<void(bool)>& callback) { |
- web_view_permission_helper_->RequestPointerLockPermission( |
- user_gesture, |
- last_unlocked_by_target, |
- callback); |
+void WebViewGuest::GuestZoomChanged(double old_zoom_level, |
+ double new_zoom_level) { |
+ // Dispatch the zoomchange event. |
+ double old_zoom_factor = ConvertZoomLevelToZoomFactor(old_zoom_level); |
+ double new_zoom_factor = ConvertZoomLevelToZoomFactor(new_zoom_level); |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetDouble(webview::kOldZoomFactor, old_zoom_factor); |
+ args->SetDouble(webview::kNewZoomFactor, new_zoom_factor); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventZoomChange, args.Pass())); |
+} |
+ |
+bool WebViewGuest::IsAutoSizeSupported() const { |
+ return true; |
+} |
+ |
+void WebViewGuest::SetContextMenuPosition(const gfx::Point& position) { |
+ if (web_view_guest_delegate_) |
+ web_view_guest_delegate_->SetContextMenuPosition(position); |
} |
void WebViewGuest::SignalWhenReady(const base::Closure& callback) { |
@@ -995,227 +798,136 @@ void WebViewGuest::WillAttachToEmbedder() { |
PushWebViewStateToIOThread(); |
} |
-content::JavaScriptDialogManager* WebViewGuest::GetJavaScriptDialogManager( |
- WebContents* source) { |
- return &javascript_dialog_helper_; |
+void WebViewGuest::WillDestroy() { |
+ if (!attached() && GetOpener()) |
+ GetOpener()->pending_new_windows_.erase(this); |
} |
-void WebViewGuest::NavigateGuest(const std::string& src, |
- bool force_navigation) { |
- if (src.empty()) |
- return; |
- |
- GURL url = ResolveURL(src); |
- |
- // We wait for all the content scripts to load and then navigate the guest |
- // if the navigation is embedder-initiated. For browser-initiated navigations, |
- // content scripts will be ready. |
- if (force_navigation) { |
- SignalWhenReady(base::Bind( |
- &WebViewGuest::LoadURLWithParams, weak_ptr_factory_.GetWeakPtr(), url, |
- content::Referrer(), ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
- GlobalRequestID(), force_navigation)); |
- return; |
+void WebViewGuest::Observe(int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details) { |
+ switch (type) { |
+ case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: { |
+ DCHECK_EQ(content::Source<WebContents>(source).ptr(), web_contents()); |
+ if (content::Source<WebContents>(source).ptr() == web_contents()) |
+ LoadHandlerCalled(); |
+ break; |
+ } |
+ case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: { |
+ DCHECK_EQ(content::Source<WebContents>(source).ptr(), web_contents()); |
+ content::ResourceRedirectDetails* resource_redirect_details = |
+ content::Details<content::ResourceRedirectDetails>(details).ptr(); |
+ bool is_top_level = resource_redirect_details->resource_type == |
+ content::RESOURCE_TYPE_MAIN_FRAME; |
+ LoadRedirect(resource_redirect_details->url, |
+ resource_redirect_details->new_url, is_top_level); |
+ break; |
+ } |
+ default: |
+ NOTREACHED() << "Unexpected notification sent."; |
+ break; |
} |
- LoadURLWithParams(url, content::Referrer(), ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
- GlobalRequestID(), force_navigation); |
} |
-bool WebViewGuest::HandleKeyboardShortcuts( |
- const content::NativeWebKeyboardEvent& event) { |
- // <webview> outside of Chrome Apps do not handle keyboard shortcuts. |
- if (!GuestViewManager::FromBrowserContext(browser_context())-> |
- IsOwnedByExtension(this)) { |
- return false; |
- } |
- |
- if (event.type != blink::WebInputEvent::RawKeyDown) |
- return false; |
- |
- // If the user hits the escape key without any modifiers then unlock the |
- // mouse if necessary. |
- if ((event.windowsKeyCode == ui::VKEY_ESCAPE) && |
- !(event.modifiers & blink::WebInputEvent::InputModifiers)) { |
- return web_contents()->GotResponseToLockMouseRequest(false); |
- } |
- |
-#if defined(OS_MACOSX) |
- if (event.modifiers != blink::WebInputEvent::MetaKey) |
- return false; |
- |
- if (event.windowsKeyCode == ui::VKEY_OEM_4) { |
- Go(-1); |
- return true; |
- } |
- |
- if (event.windowsKeyCode == ui::VKEY_OEM_6) { |
- Go(1); |
- return true; |
- } |
-#else |
- if (event.windowsKeyCode == ui::VKEY_BROWSER_BACK) { |
- Go(-1); |
- return true; |
- } |
- |
- if (event.windowsKeyCode == ui::VKEY_BROWSER_FORWARD) { |
- Go(1); |
- return true; |
- } |
-#endif |
- |
- return false; |
+bool WebViewGuest::AddMessageToConsole(WebContents* source, |
+ int32 level, |
+ const base::string16& message, |
+ int32 line_no, |
+ const base::string16& source_id) { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ // Log levels are from base/logging.h: LogSeverity. |
+ args->SetInteger(webview::kLevel, level); |
+ args->SetString(webview::kMessage, message); |
+ args->SetInteger(webview::kLine, line_no); |
+ args->SetString(webview::kSourceId, source_id); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventConsoleMessage, args.Pass())); |
+ return true; |
} |
-void WebViewGuest::ApplyAttributes(const base::DictionaryValue& params) { |
- std::string name; |
- if (params.GetString(webview::kAttributeName, &name)) { |
- // If the guest window's name is empty, then the WebView tag's name is |
- // assigned. Otherwise, the guest window's name takes precedence over the |
- // WebView tag's name. |
- if (name_.empty()) |
- SetName(name); |
- } |
- if (attached()) |
- ReportFrameNameChange(name_); |
- |
- std::string user_agent_override; |
- params.GetString(webview::kParameterUserAgentOverride, &user_agent_override); |
- SetUserAgentOverride(user_agent_override); |
- |
- bool allow_transparency = false; |
- if (params.GetBoolean(webview::kAttributeAllowTransparency, |
- &allow_transparency)) { |
- // We need to set the background opaque flag after navigation to ensure that |
- // there is a RenderWidgetHostView available. |
- SetAllowTransparency(allow_transparency); |
- } |
- |
- bool allow_scaling = false; |
- if (params.GetBoolean(webview::kAttributeAllowScaling, &allow_scaling)) |
- SetAllowScaling(allow_scaling); |
- |
- // Check for a pending zoom from before the first navigation. |
- params.GetDouble(webview::kInitialZoomFactor, &pending_zoom_factor_); |
- |
- bool is_pending_new_window = false; |
- if (GetOpener()) { |
- // We need to do a navigation here if the target URL has changed between |
- // the time the WebContents was created and the time it was attached. |
- // We also need to do an initial navigation if a RenderView was never |
- // created for the new window in cases where there is no referrer. |
- auto it = GetOpener()->pending_new_windows_.find(this); |
- if (it != GetOpener()->pending_new_windows_.end()) { |
- const NewWindowInfo& new_window_info = it->second; |
- if (new_window_info.changed || !web_contents()->HasOpener()) |
- NavigateGuest(new_window_info.url.spec(), false /* force_navigation */); |
- |
- // Once a new guest is attached to the DOM of the embedder page, then the |
- // lifetime of the new guest is no longer managed by the opener guest. |
- GetOpener()->pending_new_windows_.erase(this); |
- |
- is_pending_new_window = true; |
- } |
- } |
- |
- // Only read the src attribute if this is not a New Window API flow. |
- if (!is_pending_new_window) { |
- std::string src; |
- if (params.GetString(webview::kAttributeSrc, &src)) |
- NavigateGuest(src, true /* force_navigation */); |
- } |
+void WebViewGuest::CloseContents(WebContents* source) { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ DispatchEventToView(new GuestViewEvent(webview::kEventClose, args.Pass())); |
} |
-void WebViewGuest::ShowContextMenu( |
- int request_id, |
- const WebViewGuestDelegate::MenuItemVector* items) { |
- if (web_view_guest_delegate_) |
- web_view_guest_delegate_->OnShowContextMenu(request_id, items); |
+bool WebViewGuest::HandleContextMenu(const content::ContextMenuParams& params) { |
+ if (!web_view_guest_delegate_) |
+ return false; |
+ return web_view_guest_delegate_->HandleContextMenu(params); |
} |
-void WebViewGuest::SetName(const std::string& name) { |
- if (name_ == name) |
+void WebViewGuest::HandleKeyboardEvent( |
+ WebContents* source, |
+ const content::NativeWebKeyboardEvent& event) { |
+ if (HandleKeyboardShortcuts(event)) |
return; |
- name_ = name; |
- Send(new ExtensionMsg_SetFrameName(routing_id(), name_)); |
+ GuestViewBase::HandleKeyboardEvent(source, event); |
} |
-void WebViewGuest::SetZoom(double zoom_factor) { |
- auto zoom_controller = ZoomController::FromWebContents(web_contents()); |
- DCHECK(zoom_controller); |
- double zoom_level = content::ZoomFactorToZoomLevel(zoom_factor); |
- zoom_controller->SetZoomLevel(zoom_level); |
+void WebViewGuest::LoadProgressChanged(WebContents* source, double progress) { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetString(guest_view::kUrl, web_contents()->GetURL().spec()); |
+ args->SetDouble(webview::kProgress, progress); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventLoadProgress, args.Pass())); |
} |
-void WebViewGuest::SetZoomMode(ZoomController::ZoomMode zoom_mode) { |
- ZoomController::FromWebContents(web_contents())->SetZoomMode(zoom_mode); |
+bool WebViewGuest::PreHandleGestureEvent(WebContents* source, |
+ const blink::WebGestureEvent& event) { |
+ return !allow_scaling_ && GuestViewBase::PreHandleGestureEvent(source, event); |
} |
-void WebViewGuest::SetAllowTransparency(bool allow) { |
- if (allow_transparency_ == allow) |
- return; |
- |
- allow_transparency_ = allow; |
- if (!web_contents()->GetRenderViewHost()->GetView()) |
- return; |
- |
- if (allow_transparency_) { |
- web_contents()->GetRenderViewHost()->GetView()->SetBackgroundColor( |
- SK_ColorTRANSPARENT); |
- } else { |
- web_contents() |
- ->GetRenderViewHost() |
- ->GetView() |
- ->SetBackgroundColorToDefault(); |
- } |
+// TODO(fsamuel): Find a reliable way to test the 'responsive' and |
+// 'unresponsive' events. |
+void WebViewGuest::RendererResponsive(WebContents* source) { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetInteger(webview::kProcessId, |
+ web_contents()->GetRenderProcessHost()->GetID()); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventResponsive, args.Pass())); |
} |
-void WebViewGuest::SetAllowScaling(bool allow) { |
- allow_scaling_ = allow; |
+void WebViewGuest::RendererUnresponsive(WebContents* source) { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetInteger(webview::kProcessId, |
+ web_contents()->GetRenderProcessHost()->GetID()); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventUnresponsive, args.Pass())); |
} |
-bool WebViewGuest::LoadDataWithBaseURL(const std::string& data_url, |
- const std::string& base_url, |
- const std::string& virtual_url, |
- std::string* error) { |
- // Make GURLs from URLs. |
- const GURL data_gurl = GURL(data_url); |
- const GURL base_gurl = GURL(base_url); |
- const GURL virtual_gurl = GURL(virtual_url); |
+void WebViewGuest::RequestMediaAccessPermission( |
+ WebContents* source, |
+ const content::MediaStreamRequest& request, |
+ const content::MediaResponseCallback& callback) { |
+ web_view_permission_helper_->RequestMediaAccessPermission(source, request, |
+ callback); |
+} |
- // Check that the provided URLs are valid. |
- // |data_url| must be a valid data URL. |
- if (!data_gurl.is_valid() || !data_gurl.SchemeIs(url::kDataScheme)) { |
- base::SStringPrintf( |
- error, webview::kAPILoadDataInvalidDataURL, data_url.c_str()); |
- return false; |
- } |
- // |base_url| must be a valid URL. |
- if (!base_gurl.is_valid()) { |
- base::SStringPrintf( |
- error, webview::kAPILoadDataInvalidBaseURL, base_url.c_str()); |
- return false; |
- } |
- // |virtual_url| must be a valid URL. |
- if (!virtual_gurl.is_valid()) { |
- base::SStringPrintf( |
- error, webview::kAPILoadDataInvalidVirtualURL, virtual_url.c_str()); |
- return false; |
- } |
+void WebViewGuest::RequestPointerLockPermission( |
+ bool user_gesture, |
+ bool last_unlocked_by_target, |
+ const base::Callback<void(bool)>& callback) { |
+ web_view_permission_helper_->RequestPointerLockPermission( |
+ user_gesture, last_unlocked_by_target, callback); |
+} |
- // Set up the parameters to load |data_url| with the specified |base_url|. |
- content::NavigationController::LoadURLParams load_params(data_gurl); |
- load_params.load_type = content::NavigationController::LOAD_TYPE_DATA; |
- load_params.base_url_for_data_url = base_gurl; |
- load_params.virtual_url_for_data_url = virtual_gurl; |
- load_params.override_user_agent = |
- content::NavigationController::UA_OVERRIDE_INHERIT; |
+bool WebViewGuest::CheckMediaAccessPermission(WebContents* source, |
+ const GURL& security_origin, |
+ content::MediaStreamType type) { |
+ return web_view_permission_helper_->CheckMediaAccessPermission( |
+ source, security_origin, type); |
+} |
- // Navigate to the data URL. |
- GuestViewBase::LoadURLWithParams(load_params); |
+void WebViewGuest::CanDownload(const GURL& url, |
+ const std::string& request_method, |
+ const base::Callback<void(bool)>& callback) { |
+ web_view_permission_helper_->CanDownload(url, request_method, callback); |
+} |
- return true; |
+content::JavaScriptDialogManager* WebViewGuest::GetJavaScriptDialogManager( |
+ WebContents* source) { |
+ return &javascript_dialog_helper_; |
} |
void WebViewGuest::AddNewContents(WebContents* source, |
@@ -1291,53 +1003,212 @@ WebContents* WebViewGuest::OpenURLFromTab( |
return web_contents(); |
} |
- // This code path is taken if Ctrl+Click, middle click or any of the |
- // keyboard/mouse combinations are used to open a link in a new tab/window. |
- // This code path is also taken on client-side redirects from about:blank. |
- CreateNewGuestWebViewWindow(params); |
- return nullptr; |
+ // This code path is taken if Ctrl+Click, middle click or any of the |
+ // keyboard/mouse combinations are used to open a link in a new tab/window. |
+ // This code path is also taken on client-side redirects from about:blank. |
+ CreateNewGuestWebViewWindow(params); |
+ return nullptr; |
+} |
+ |
+void WebViewGuest::WebContentsCreated(WebContents* source_contents, |
+ int opener_render_frame_id, |
+ const std::string& frame_name, |
+ const GURL& target_url, |
+ WebContents* new_contents) { |
+ auto guest = WebViewGuest::FromWebContents(new_contents); |
+ CHECK(guest); |
+ guest->SetOpener(this); |
+ guest->name_ = frame_name; |
+ pending_new_windows_.insert( |
+ std::make_pair(guest, NewWindowInfo(target_url, frame_name))); |
+} |
+ |
+void WebViewGuest::EnterFullscreenModeForTab(WebContents* web_contents, |
+ const GURL& origin) { |
+ // Ask the embedder for permission. |
+ base::DictionaryValue request_info; |
+ request_info.SetString(webview::kOrigin, origin.spec()); |
+ web_view_permission_helper_->RequestPermission( |
+ WEB_VIEW_PERMISSION_TYPE_FULLSCREEN, request_info, |
+ base::Bind(&WebViewGuest::OnFullscreenPermissionDecided, |
+ weak_ptr_factory_.GetWeakPtr()), |
+ false /* allowed_by_default */); |
+ |
+ // TODO(lazyboy): Right now the guest immediately goes fullscreen within its |
+ // bounds. If the embedder denies the permission then we will see a flicker. |
+ // Once we have the ability to "cancel" a renderer/ fullscreen request: |
+ // http://crbug.com/466854 this won't be necessary and we should be |
+ // Calling SetFullscreenState(true) once the embedder allowed the request. |
+ // Otherwise we would cancel renderer/ fullscreen if the embedder denied. |
+ SetFullscreenState(true); |
+} |
+ |
+void WebViewGuest::ExitFullscreenModeForTab(WebContents* web_contents) { |
+ SetFullscreenState(false); |
+} |
+ |
+bool WebViewGuest::IsFullscreenForTabOrPending( |
+ const WebContents* web_contents) const { |
+ return is_guest_fullscreen_; |
+} |
+ |
+void WebViewGuest::DidCommitProvisionalLoadForFrame( |
+ content::RenderFrameHost* render_frame_host, |
+ const GURL& url, |
+ ui::PageTransition transition_type) { |
+ if (!render_frame_host->GetParent()) { |
+ src_ = url; |
+ // Handle a pending zoom if one exists. |
+ if (pending_zoom_factor_) { |
+ SetZoom(pending_zoom_factor_); |
+ pending_zoom_factor_ = 0.0; |
+ } |
+ } |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetString(guest_view::kUrl, url.spec()); |
+ args->SetBoolean(guest_view::kIsTopLevel, !render_frame_host->GetParent()); |
+ args->SetString(webview::kInternalBaseURLForDataURL, |
+ web_contents() |
+ ->GetController() |
+ .GetLastCommittedEntry() |
+ ->GetBaseURLForDataURL() |
+ .spec()); |
+ args->SetInteger(webview::kInternalCurrentEntryIndex, |
+ web_contents()->GetController().GetCurrentEntryIndex()); |
+ args->SetInteger(webview::kInternalEntryCount, |
+ web_contents()->GetController().GetEntryCount()); |
+ args->SetInteger(webview::kInternalProcessId, |
+ web_contents()->GetRenderProcessHost()->GetID()); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventLoadCommit, args.Pass())); |
+ |
+ find_helper_.CancelAllFindSessions(); |
+} |
+ |
+void WebViewGuest::DidFailProvisionalLoad( |
+ content::RenderFrameHost* render_frame_host, |
+ const GURL& validated_url, |
+ int error_code, |
+ const base::string16& error_description, |
+ bool was_ignored_by_handler) { |
+ // Suppress loadabort for "mailto" URLs. |
+ if (validated_url.SchemeIs(url::kMailToScheme)) |
+ return; |
+ |
+ LoadAbort(!render_frame_host->GetParent(), validated_url, error_code, |
+ net::ErrorToShortString(error_code)); |
+} |
+ |
+void WebViewGuest::DidStartProvisionalLoadForFrame( |
+ content::RenderFrameHost* render_frame_host, |
+ const GURL& validated_url, |
+ bool is_error_page, |
+ bool is_iframe_srcdoc) { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetString(guest_view::kUrl, validated_url.spec()); |
+ args->SetBoolean(guest_view::kIsTopLevel, !render_frame_host->GetParent()); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventLoadStart, args.Pass())); |
+} |
+ |
+void WebViewGuest::RenderProcessGone(base::TerminationStatus status) { |
+ // Cancel all find sessions in progress. |
+ find_helper_.CancelAllFindSessions(); |
+ |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetInteger(webview::kProcessId, |
+ web_contents()->GetRenderProcessHost()->GetID()); |
+ args->SetString(webview::kReason, TerminationStatusToString(status)); |
+ DispatchEventToView(new GuestViewEvent(webview::kEventExit, args.Pass())); |
+} |
+ |
+void WebViewGuest::UserAgentOverrideSet(const std::string& user_agent) { |
+ content::NavigationController& controller = web_contents()->GetController(); |
+ content::NavigationEntry* entry = controller.GetVisibleEntry(); |
+ if (!entry) |
+ return; |
+ entry->SetIsOverridingUserAgent(!user_agent.empty()); |
+ web_contents()->GetController().Reload(false); |
+} |
+ |
+void WebViewGuest::FrameNameChanged(RenderFrameHost* render_frame_host, |
+ const std::string& name) { |
+ if (render_frame_host->GetParent()) |
+ return; |
+ |
+ if (name_ == name) |
+ return; |
+ |
+ ReportFrameNameChange(name); |
} |
-void WebViewGuest::WebContentsCreated(WebContents* source_contents, |
- int opener_render_frame_id, |
- const std::string& frame_name, |
- const GURL& target_url, |
- WebContents* new_contents) { |
- auto guest = WebViewGuest::FromWebContents(new_contents); |
- CHECK(guest); |
- guest->SetOpener(this); |
- guest->name_ = frame_name; |
- pending_new_windows_.insert( |
- std::make_pair(guest, NewWindowInfo(target_url, frame_name))); |
+void WebViewGuest::ReportFrameNameChange(const std::string& name) { |
+ name_ = name; |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetString(webview::kName, name); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventFrameNameChanged, args.Pass())); |
} |
-void WebViewGuest::EnterFullscreenModeForTab(WebContents* web_contents, |
- const GURL& origin) { |
- // Ask the embedder for permission. |
- base::DictionaryValue request_info; |
- request_info.SetString(webview::kOrigin, origin.spec()); |
- web_view_permission_helper_->RequestPermission( |
- WEB_VIEW_PERMISSION_TYPE_FULLSCREEN, request_info, |
- base::Bind(&WebViewGuest::OnFullscreenPermissionDecided, |
- weak_ptr_factory_.GetWeakPtr()), |
- false /* allowed_by_default */); |
+void WebViewGuest::LoadHandlerCalled() { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventContentLoad, args.Pass())); |
+} |
- // TODO(lazyboy): Right now the guest immediately goes fullscreen within its |
- // bounds. If the embedder denies the permission then we will see a flicker. |
- // Once we have the ability to "cancel" a renderer/ fullscreen request: |
- // http://crbug.com/466854 this won't be necessary and we should be |
- // Calling SetFullscreenState(true) once the embedder allowed the request. |
- // Otherwise we would cancel renderer/ fullscreen if the embedder denied. |
- SetFullscreenState(true); |
+void WebViewGuest::LoadRedirect(const GURL& old_url, |
+ const GURL& new_url, |
+ bool is_top_level) { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetBoolean(guest_view::kIsTopLevel, is_top_level); |
+ args->SetString(webview::kNewURL, new_url.spec()); |
+ args->SetString(webview::kOldURL, old_url.spec()); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventLoadRedirect, args.Pass())); |
} |
-void WebViewGuest::ExitFullscreenModeForTab(WebContents* web_contents) { |
- SetFullscreenState(false); |
+void WebViewGuest::PushWebViewStateToIOThread() { |
+ const GURL& site_url = web_contents()->GetSiteInstance()->GetSiteURL(); |
+ std::string partition_domain; |
+ std::string partition_id; |
+ bool in_memory; |
+ if (!GetGuestPartitionConfigForSite(site_url, &partition_domain, |
+ &partition_id, &in_memory)) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ |
+ WebViewRendererState::WebViewInfo web_view_info; |
+ web_view_info.embedder_process_id = |
+ owner_web_contents()->GetRenderProcessHost()->GetID(); |
+ web_view_info.instance_id = view_instance_id(); |
+ web_view_info.partition_id = partition_id; |
+ web_view_info.owner_host = owner_host(); |
+ web_view_info.rules_registry_id = rules_registry_id_; |
+ |
+ // Get content scripts IDs added by the guest. |
+ WebViewContentScriptManager* manager = |
+ WebViewContentScriptManager::Get(browser_context()); |
+ DCHECK(manager); |
+ web_view_info.content_script_ids = manager->GetContentScriptIDSet( |
+ web_view_info.embedder_process_id, web_view_info.instance_id); |
+ |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&WebViewRendererState::AddGuest, |
+ base::Unretained(WebViewRendererState::GetInstance()), |
+ web_contents()->GetRenderProcessHost()->GetID(), |
+ web_contents()->GetRoutingID(), web_view_info)); |
} |
-bool WebViewGuest::IsFullscreenForTabOrPending( |
- const WebContents* web_contents) const { |
- return is_guest_fullscreen_; |
+// static |
+void WebViewGuest::RemoveWebViewStateFromIOThread(WebContents* web_contents) { |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&WebViewRendererState::RemoveGuest, |
+ base::Unretained(WebViewRendererState::GetInstance()), |
+ web_contents->GetRenderProcessHost()->GetID(), |
+ web_contents->GetRoutingID())); |
} |
void WebViewGuest::LoadURLWithParams( |
@@ -1444,50 +1315,155 @@ GURL WebViewGuest::ResolveURL(const std::string& src) { |
return default_url.Resolve(src); |
} |
-void WebViewGuest::OnWebViewNewWindowResponse( |
- int new_window_instance_id, |
- bool allow, |
- const std::string& user_input) { |
- auto guest = |
- WebViewGuest::From(owner_web_contents()->GetRenderProcessHost()->GetID(), |
- new_window_instance_id); |
- if (!guest) |
- return; |
+void WebViewGuest::LoadAbort(bool is_top_level, |
+ const GURL& url, |
+ int error_code, |
+ const std::string& error_type) { |
+ scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
+ args->SetBoolean(guest_view::kIsTopLevel, is_top_level); |
+ args->SetString(guest_view::kUrl, url.possibly_invalid_spec()); |
+ args->SetInteger(guest_view::kCode, error_code); |
+ args->SetString(guest_view::kReason, error_type); |
+ DispatchEventToView( |
+ new GuestViewEvent(webview::kEventLoadAbort, args.Pass())); |
+} |
- if (!allow) |
- guest->Destroy(); |
+void WebViewGuest::CreateNewGuestWebViewWindow( |
+ const content::OpenURLParams& params) { |
+ GuestViewManager* guest_manager = |
+ GuestViewManager::FromBrowserContext(browser_context()); |
+ // Set the attach params to use the same partition as the opener. |
+ // We pull the partition information from the site's URL, which is of the |
+ // form guest://site/{persist}?{partition_name}. |
+ const GURL& site_url = web_contents()->GetSiteInstance()->GetSiteURL(); |
+ const std::string storage_partition_id = |
+ GetStoragePartitionIdFromSiteURL(site_url); |
+ base::DictionaryValue create_params; |
+ create_params.SetString(webview::kStoragePartitionId, storage_partition_id); |
+ |
+ guest_manager->CreateGuest( |
+ WebViewGuest::Type, embedder_web_contents(), create_params, |
+ base::Bind(&WebViewGuest::NewGuestWebViewCallback, |
+ weak_ptr_factory_.GetWeakPtr(), params)); |
} |
-void WebViewGuest::OnFullscreenPermissionDecided( |
- bool allowed, |
- const std::string& user_input) { |
- last_fullscreen_permission_was_allowed_by_embedder_ = allowed; |
- SetFullscreenState(allowed); |
+void WebViewGuest::NewGuestWebViewCallback(const content::OpenURLParams& params, |
+ WebContents* guest_web_contents) { |
+ WebViewGuest* new_guest = WebViewGuest::FromWebContents(guest_web_contents); |
+ new_guest->SetOpener(this); |
+ |
+ // Take ownership of |new_guest|. |
+ pending_new_windows_.insert( |
+ std::make_pair(new_guest, NewWindowInfo(params.url, std::string()))); |
+ |
+ // Request permission to show the new window. |
+ RequestNewWindowPermission(params.disposition, gfx::Rect(), |
+ params.user_gesture, new_guest->web_contents()); |
} |
-bool WebViewGuest::GuestMadeEmbedderFullscreen() const { |
- return last_fullscreen_permission_was_allowed_by_embedder_ && |
- is_embedder_fullscreen_; |
+bool WebViewGuest::HandleKeyboardShortcuts( |
+ const content::NativeWebKeyboardEvent& event) { |
+ // <webview> outside of Chrome Apps do not handle keyboard shortcuts. |
+ if (!GuestViewManager::FromBrowserContext(browser_context()) |
+ ->IsOwnedByExtension(this)) { |
+ return false; |
+ } |
+ |
+ if (event.type != blink::WebInputEvent::RawKeyDown) |
+ return false; |
+ |
+ // If the user hits the escape key without any modifiers then unlock the |
+ // mouse if necessary. |
+ if ((event.windowsKeyCode == ui::VKEY_ESCAPE) && |
+ !(event.modifiers & blink::WebInputEvent::InputModifiers)) { |
+ return web_contents()->GotResponseToLockMouseRequest(false); |
+ } |
+ |
+#if defined(OS_MACOSX) |
+ if (event.modifiers != blink::WebInputEvent::MetaKey) |
+ return false; |
+ |
+ if (event.windowsKeyCode == ui::VKEY_OEM_4) { |
+ Go(-1); |
+ return true; |
+ } |
+ |
+ if (event.windowsKeyCode == ui::VKEY_OEM_6) { |
+ Go(1); |
+ return true; |
+ } |
+#else |
+ if (event.windowsKeyCode == ui::VKEY_BROWSER_BACK) { |
+ Go(-1); |
+ return true; |
+ } |
+ |
+ if (event.windowsKeyCode == ui::VKEY_BROWSER_FORWARD) { |
+ Go(1); |
+ return true; |
+ } |
+#endif |
+ |
+ return false; |
} |
-void WebViewGuest::SetFullscreenState(bool is_fullscreen) { |
- if (is_fullscreen == is_guest_fullscreen_) |
- return; |
+void WebViewGuest::ApplyAttributes(const base::DictionaryValue& params) { |
+ std::string name; |
+ if (params.GetString(webview::kAttributeName, &name)) { |
+ // If the guest window's name is empty, then the WebView tag's name is |
+ // assigned. Otherwise, the guest window's name takes precedence over the |
+ // WebView tag's name. |
+ if (name_.empty()) |
+ SetName(name); |
+ } |
+ if (attached()) |
+ ReportFrameNameChange(name_); |
- bool was_fullscreen = is_guest_fullscreen_; |
- is_guest_fullscreen_ = is_fullscreen; |
- // If the embedder entered fullscreen because of us, it should exit fullscreen |
- // when we exit fullscreen. |
- if (was_fullscreen && GuestMadeEmbedderFullscreen()) { |
- // Dispatch a message so we can call document.webkitCancelFullscreen() |
- // on the embedder. |
- scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); |
- DispatchEventToView( |
- new GuestViewEvent(webview::kEventExitFullscreen, args.Pass())); |
+ std::string user_agent_override; |
+ params.GetString(webview::kParameterUserAgentOverride, &user_agent_override); |
+ SetUserAgentOverride(user_agent_override); |
+ |
+ bool allow_transparency = false; |
+ if (params.GetBoolean(webview::kAttributeAllowTransparency, |
+ &allow_transparency)) { |
+ // We need to set the background opaque flag after navigation to ensure that |
+ // there is a RenderWidgetHostView available. |
+ SetAllowTransparency(allow_transparency); |
+ } |
+ |
+ bool allow_scaling = false; |
+ if (params.GetBoolean(webview::kAttributeAllowScaling, &allow_scaling)) |
+ SetAllowScaling(allow_scaling); |
+ |
+ // Check for a pending zoom from before the first navigation. |
+ params.GetDouble(webview::kInitialZoomFactor, &pending_zoom_factor_); |
+ |
+ bool is_pending_new_window = false; |
+ if (GetOpener()) { |
+ // We need to do a navigation here if the target URL has changed between |
+ // the time the WebContents was created and the time it was attached. |
+ // We also need to do an initial navigation if a RenderView was never |
+ // created for the new window in cases where there is no referrer. |
+ auto it = GetOpener()->pending_new_windows_.find(this); |
+ if (it != GetOpener()->pending_new_windows_.end()) { |
+ const NewWindowInfo& new_window_info = it->second; |
+ if (new_window_info.changed || !web_contents()->HasOpener()) |
+ NavigateGuest(new_window_info.url.spec(), false /* force_navigation */); |
+ |
+ // Once a new guest is attached to the DOM of the embedder page, then the |
+ // lifetime of the new guest is no longer managed by the opener guest. |
+ GetOpener()->pending_new_windows_.erase(this); |
+ |
+ is_pending_new_window = true; |
+ } |
+ } |
+ |
+ // Only read the src attribute if this is not a New Window API flow. |
+ if (!is_pending_new_window) { |
+ std::string src; |
+ if (params.GetString(webview::kAttributeSrc, &src)) |
+ NavigateGuest(src, true /* force_navigation */); |
} |
- // Since we changed fullscreen state, sending a Resize message ensures that |
- // renderer/ sees the change. |
- web_contents()->GetRenderViewHost()->WasResized(); |
} |
} // namespace extensions |