mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	Add chrome.tabs.create API support (issue #1947)
This commit is contained in:
		| @@ -7,11 +7,16 @@ | ||||
| #include "libcef/browser/browser_context_impl.h" | ||||
| #include "libcef/browser/extensions/browser_extensions_util.h" | ||||
| #include "libcef/browser/extensions/extension_system.h" | ||||
| #include "libcef/browser/navigate_params.h" | ||||
| #include "libcef/browser/thread_util.h" | ||||
|  | ||||
| #include "base/strings/utf_string_conversions.h" | ||||
| #include "base/task_scheduler/post_task.h" | ||||
| #include "chrome/browser/extensions/api/tabs/tabs_constants.h" | ||||
| #include "chrome/browser/extensions/extension_tab_util.h" | ||||
| #include "chrome/browser/profiles/profile.h" | ||||
| #include "content/public/browser/favicon_status.h" | ||||
| #include "content/public/browser/navigation_entry.h" | ||||
| #include "extensions/browser/extension_function.h" | ||||
| #include "extensions/browser/extension_function_dispatcher.h" | ||||
| #include "extensions/common/error_utils.h" | ||||
| @@ -208,13 +213,12 @@ CefRefPtr<CefBrowserHostImpl> | ||||
| CefExtensionFunctionDetails::GetBrowserForTabIdFirstTime( | ||||
|     int tab_id, | ||||
|     std::string* error_message) const { | ||||
|   DCHECK_GE(tab_id, -1); | ||||
|   DCHECK(!get_browser_called_first_time_); | ||||
|   get_browser_called_first_time_ = true; | ||||
|  | ||||
|   CefRefPtr<CefBrowserHostImpl> browser; | ||||
|  | ||||
|   if (tab_id != -1) { | ||||
|   if (tab_id >= 0) { | ||||
|     // May be an invalid tabId or in the wrong BrowserContext. | ||||
|     browser = GetBrowserForTabId(tab_id, function_->browser_context()); | ||||
|     if (!browser || !browser->web_contents() || !CanAccessBrowser(browser)) { | ||||
| @@ -277,6 +281,184 @@ bool CefExtensionFunctionDetails::LoadFile(const std::string& file, | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| CefExtensionFunctionDetails::OpenTabParams::OpenTabParams() {} | ||||
|  | ||||
| CefExtensionFunctionDetails::OpenTabParams::~OpenTabParams() {} | ||||
|  | ||||
| base::DictionaryValue* CefExtensionFunctionDetails::OpenTab( | ||||
|     const OpenTabParams& params, | ||||
|     bool user_gesture, | ||||
|     std::string* error_message) const { | ||||
|   CefRefPtr<CefBrowserHostImpl> sender_browser = GetSenderBrowser(); | ||||
|   if (!sender_browser) | ||||
|     return nullptr; | ||||
|  | ||||
|   // windowId defaults to "current" window. | ||||
|   int window_id = extension_misc::kCurrentWindowId; | ||||
|   if (params.window_id.get()) | ||||
|     window_id = *params.window_id; | ||||
|  | ||||
|   // CEF doesn't have the concept of windows containing tab strips so we'll | ||||
|   // select an "active browser" for BrowserContext sharing instead. | ||||
|   CefRefPtr<CefBrowserHostImpl> active_browser = | ||||
|       GetBrowserForTabIdFirstTime(window_id, error_message); | ||||
|   if (!active_browser) | ||||
|     return nullptr; | ||||
|  | ||||
|   // If an opener browser was specified then we expect it to exist. | ||||
|   int opener_browser_id = -1; | ||||
|   if (params.opener_tab_id.get() && *params.opener_tab_id >= 0) { | ||||
|     if (GetBrowserForTabIdAgain(*params.opener_tab_id, error_message)) { | ||||
|       opener_browser_id = *params.opener_tab_id; | ||||
|     } else { | ||||
|       return nullptr; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   GURL url; | ||||
|   if (params.url.get()) { | ||||
|     std::string url_string = *params.url; | ||||
|     url = ExtensionTabUtil::ResolvePossiblyRelativeURL(url_string, | ||||
|                                                        function()->extension()); | ||||
|     if (!url.is_valid()) { | ||||
|       if (error_message) { | ||||
|         *error_message = | ||||
|             ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, url_string); | ||||
|       } | ||||
|       return nullptr; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Don't let extensions crash the browser or renderers. | ||||
|   if (ExtensionTabUtil::IsKillURL(url)) { | ||||
|     if (error_message) | ||||
|       *error_message = keys::kNoCrashBrowserError; | ||||
|     return nullptr; | ||||
|   } | ||||
|  | ||||
|   // Default to foreground for the new tab. The presence of 'active' property | ||||
|   // will override this default. | ||||
|   bool active = true; | ||||
|   if (params.active.get()) | ||||
|     active = *params.active; | ||||
|  | ||||
|   // CEF doesn't use the index value but we let the client see/modify it. | ||||
|   int index = 0; | ||||
|   if (params.index.get()) | ||||
|     index = *params.index; | ||||
|  | ||||
|   CefBrowserContextImpl* browser_context_impl = | ||||
|       CefBrowserContextImpl::GetForContext(active_browser->GetBrowserContext()); | ||||
|  | ||||
|   // A CEF representation should always exist. | ||||
|   CefRefPtr<CefExtension> cef_extension = | ||||
|       browser_context_impl->extension_system()->GetExtension( | ||||
|           function()->extension()->id()); | ||||
|   DCHECK(cef_extension); | ||||
|   if (!cef_extension) | ||||
|     return nullptr; | ||||
|  | ||||
|   // Always use the same request context that the extension was registered with. | ||||
|   // May represent an *Impl or *Proxy BrowserContext. | ||||
|   // GetLoaderContext() will return NULL for internal extensions. | ||||
|   CefRefPtr<CefRequestContext> request_context = | ||||
|       cef_extension->GetLoaderContext(); | ||||
|   if (!request_context) | ||||
|     return nullptr; | ||||
|  | ||||
|   CefBrowserHostImpl::CreateParams create_params; | ||||
|   create_params.url = url; | ||||
|   create_params.request_context = request_context; | ||||
|   create_params.window_info.reset(new CefWindowInfo); | ||||
|  | ||||
| #if defined(OS_WIN) | ||||
|   create_params.window_info->SetAsPopup(NULL, CefString()); | ||||
| #endif | ||||
|  | ||||
|   // Start with the active browser's settings. | ||||
|   create_params.client = active_browser->GetClient(); | ||||
|   create_params.settings = active_browser->settings(); | ||||
|  | ||||
|   CefRefPtr<CefExtensionHandler> handler = cef_extension->GetHandler(); | ||||
|   if (handler.get() && | ||||
|       handler->OnBeforeBrowser(cef_extension, sender_browser.get(), | ||||
|                                active_browser.get(), index, url.spec(), active, | ||||
|                                *create_params.window_info, create_params.client, | ||||
|                                create_params.settings)) { | ||||
|     // Cancel the browser creation. | ||||
|     return nullptr; | ||||
|   } | ||||
|  | ||||
|   if (active_browser->IsViewsHosted()) { | ||||
|     // The new browser will also be Views hosted. | ||||
|     create_params.window_info.reset(); | ||||
|   } | ||||
|  | ||||
|   // Browser creation may fail under certain rare circumstances. | ||||
|   CefRefPtr<CefBrowserHostImpl> new_browser = | ||||
|       CefBrowserHostImpl::Create(create_params); | ||||
|   if (!new_browser) | ||||
|     return nullptr; | ||||
|  | ||||
|   // Return data about the newly created tab. | ||||
|   auto result = CreateTabObject(new_browser, opener_browser_id, active, index); | ||||
|   ExtensionTabUtil::ScrubTabForExtension( | ||||
|       function()->extension(), new_browser->web_contents(), result.get()); | ||||
|   return result->ToValue().release(); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<api::tabs::Tab> CefExtensionFunctionDetails::CreateTabObject( | ||||
|     CefRefPtr<CefBrowserHostImpl> new_browser, | ||||
|     int opener_browser_id, | ||||
|     bool active, | ||||
|     int index) const { | ||||
|   content::WebContents* contents = new_browser->web_contents(); | ||||
|  | ||||
|   bool is_loading = contents->IsLoading(); | ||||
|   auto tab_object = base::MakeUnique<api::tabs::Tab>(); | ||||
|   tab_object->id = base::MakeUnique<int>(new_browser->GetIdentifier()); | ||||
|   tab_object->index = index; | ||||
|   tab_object->window_id = *tab_object->id; | ||||
|   tab_object->status = base::MakeUnique<std::string>( | ||||
|       is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete); | ||||
|   tab_object->active = active; | ||||
|   tab_object->selected = true; | ||||
|   tab_object->highlighted = true; | ||||
|   tab_object->pinned = false; | ||||
|   tab_object->audible = base::MakeUnique<bool>(contents->WasRecentlyAudible()); | ||||
|   tab_object->discarded = false; | ||||
|   tab_object->auto_discardable = false; | ||||
|   tab_object->muted_info = CreateMutedInfo(contents); | ||||
|   tab_object->incognito = false; | ||||
|   gfx::Size contents_size = contents->GetContainerBounds().size(); | ||||
|   tab_object->width = base::MakeUnique<int>(contents_size.width()); | ||||
|   tab_object->height = base::MakeUnique<int>(contents_size.height()); | ||||
|   tab_object->url = base::MakeUnique<std::string>(contents->GetURL().spec()); | ||||
|   tab_object->title = | ||||
|       base::MakeUnique<std::string>(base::UTF16ToUTF8(contents->GetTitle())); | ||||
|  | ||||
|   content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | ||||
|   if (entry && entry->GetFavicon().valid) { | ||||
|     tab_object->fav_icon_url = | ||||
|         base::MakeUnique<std::string>(entry->GetFavicon().url.spec()); | ||||
|   } | ||||
|  | ||||
|   if (opener_browser_id >= 0) | ||||
|     tab_object->opener_tab_id = base::MakeUnique<int>(opener_browser_id); | ||||
|  | ||||
|   return tab_object; | ||||
| } | ||||
|  | ||||
| // static | ||||
| std::unique_ptr<api::tabs::MutedInfo> | ||||
| CefExtensionFunctionDetails::CreateMutedInfo(content::WebContents* contents) { | ||||
|   DCHECK(contents); | ||||
|   std::unique_ptr<api::tabs::MutedInfo> info(new api::tabs::MutedInfo); | ||||
|   info->muted = contents->IsAudioMuted(); | ||||
|   // TODO(cef): Maybe populate |info->reason|. | ||||
|   return info; | ||||
| } | ||||
|  | ||||
| CefRefPtr<CefExtension> CefExtensionFunctionDetails::GetCefExtension() const { | ||||
|   if (!cef_extension_) { | ||||
|     cef_extension_ = | ||||
|   | ||||
		Reference in New Issue
	
	Block a user