diff --git a/atom/atom_resources.grd b/atom/atom_resources.grd
index 4336751948..2549ba1542 100644
--- a/atom/atom_resources.grd
+++ b/atom/atom_resources.grd
@@ -25,6 +25,10 @@
+
+
+
+
diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc
index 31fca948e4..4a03faf13a 100644
--- a/atom/browser/api/atom_api_app.cc
+++ b/atom/browser/api/atom_api_app.cc
@@ -532,8 +532,6 @@ void App::Observe(
content::WebContents* web_contents =
content::Source(source).ptr();
auto browser_context = web_contents->GetBrowserContext();
- auto url = web_contents->GetURL();
-
#if BUILDFLAG(ENABLE_EXTENSIONS)
// make sure background pages get a webcontents
// api wrapper so they can communicate via IPC
diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc
index 0a75cbae52..523cc910d3 100644
--- a/atom/browser/api/atom_api_web_contents.cc
+++ b/atom/browser/api/atom_api_web_contents.cc
@@ -1747,6 +1747,7 @@ void WebContents::Clone(mate::Arguments* args) {
} else {
options = mate::Dictionary::CreateEmpty(isolate());
}
+ options.Set("userGesture", true);
base::Callback callback;
if (!args->GetNext(&callback)) {
@@ -1766,18 +1767,8 @@ void WebContents::Clone(mate::Arguments* args) {
create_params.SetBoolean("clone", true);
- auto guest_view_manager =
- static_cast(GetBrowserContext()->GetGuestManager());
-
- if (!guest_view_manager) {
- callback.Run(nullptr);
- return;
- }
-
- options.Set("userGesture", true);
-
- guest_view_manager->CreateGuest(brave::TabViewGuest::Type,
- HostWebContents(),
+ extensions::TabHelper::CreateTab(HostWebContents(),
+ GetBrowserContext(),
create_params,
base::Bind(&WebContents::OnCloneCreated, base::Unretained(this), options,
base::Bind(&WebContents::OnTabCreated, base::Unretained(this),
@@ -1840,6 +1831,8 @@ void WebContents::Discard() {
if (tab_helper) {
if (!Emit("will-discard") && tab_helper->Discard())
Emit("discarded");
+ else
+ Emit("discard-aborted");
}
}
@@ -2216,6 +2209,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("getContentWindowId", &WebContents::GetContentWindowId)
.SetMethod("setActive", &WebContents::SetActive)
.SetMethod("setTabIndex", &WebContents::SetTabIndex)
+ .SetMethod("discard", &WebContents::Discard)
.SetMethod("setWebRTCIPHandlingPolicy",
&WebContents::SetWebRTCIPHandlingPolicy)
.SetMethod("getWebRTCIPHandlingPolicy",
@@ -2356,14 +2350,6 @@ void WebContents::CreateTab(mate::Arguments* args) {
auto browser_context = session->browser_context();
- auto guest_view_manager =
- static_cast(browser_context->GetGuestManager());
-
- if (!guest_view_manager) {
- args->ThrowError("No guest view manager");
- return;
- }
-
base::DictionaryValue create_params;
std::string src;
if (options.Get("src", &src) || options.Get("url", &src)) {
@@ -2373,8 +2359,8 @@ void WebContents::CreateTab(mate::Arguments* args) {
static_cast(
browser_context)->partition_with_prefix());
- guest_view_manager->CreateGuest(brave::TabViewGuest::Type,
- owner->web_contents(),
+ extensions::TabHelper::CreateTab(owner->web_contents(),
+ browser_context,
create_params,
base::Bind(&WebContents::OnTabCreated, base::Unretained(owner),
options, callback));
diff --git a/atom/browser/extensions/tab_helper.cc b/atom/browser/extensions/tab_helper.cc
index 4ac46a1c07..b24cfa277d 100644
--- a/atom/browser/extensions/tab_helper.cc
+++ b/atom/browser/extensions/tab_helper.cc
@@ -12,6 +12,7 @@
#include "atom/common/native_mate_converters/gurl_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "base/strings/utf_string_conversions.h"
+#include "brave/browser/guest_view/tab_view/tab_view_guest.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/memory/tab_manager.h"
#include "chrome/browser/sessions/session_tab_helper.h"
@@ -35,6 +36,7 @@
#include "net/base/filename_util.h"
#include "ui/base/resource/resource_bundle.h"
+using guest_view::GuestViewManager;
using memory::TabManager;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::TabHelper);
@@ -81,9 +83,97 @@ TabHelper::~TabHelper() {
BrowserList::RemoveObserver(this);
}
+// static
+void TabHelper::CreateTab(content::WebContents* owner,
+ content::BrowserContext* browser_context,
+ const base::DictionaryValue& create_params,
+ const GuestViewManager::WebContentsCreatedCallback& callback) {
+
+ auto guest_view_manager =
+ static_cast(browser_context->GetGuestManager());
+ DCHECK(guest_view_manager);
+
+ guest_view_manager->CreateGuest(brave::TabViewGuest::Type,
+ owner,
+ create_params,
+ callback);
+}
+
+// static
+content::WebContents* TabHelper::CreateTab(content::WebContents* owner,
+ content::WebContents::CreateParams create_params) {
+ auto guest_view_manager = static_cast(
+ create_params.browser_context->GetGuestManager());
+ DCHECK(guest_view_manager);
+
+ return guest_view_manager->CreateGuestWithWebContentsParams(
+ brave::TabViewGuest::Type,
+ owner,
+ create_params);
+}
+
+// static
+void TabHelper::DestroyTab(content::WebContents* tab) {
+ auto guest = brave::TabViewGuest::FromWebContents(tab);
+ DCHECK(guest);
+ guest->Destroy();
+}
+
void TabHelper::OnBrowserRemoved(Browser* browser) {
- if (browser_ == browser)
+ if (browser_ != nullptr && browser_ == browser) {
+ index_ = TabStripModel::kNoTab;
+ browser_->tab_strip_model()->RemoveObserver(this);
browser_ = nullptr;
+ }
+}
+
+void TabHelper::TabInsertedAt(TabStripModel* tab_strip_model,
+ content::WebContents* contents,
+ int index,
+ bool foreground) {
+ if (contents != web_contents())
+ return;
+
+ DCHECK(index != TabStripModel::kNoTab);
+ index_ = index;
+ // TODO(bridiver) - deal with foreground
+}
+
+void TabHelper::TabReplacedAt(TabStripModel* tab_strip_model,
+ content::WebContents* old_contents,
+ content::WebContents* new_contents,
+ int index) {
+ if (old_contents != web_contents())
+ return;
+
+ auto old_browser = browser_;
+
+ brave::TabViewGuest* old_guest = guest();
+ int guest_instance_id = old_guest->guest_instance_id();
+
+ auto new_helper = TabHelper::FromWebContents(new_contents);
+ new_helper->index_ = index_;
+ new_helper->pinned_ = pinned_;
+
+ OnBrowserRemoved(old_browser);
+ new_helper->UpdateBrowser(old_browser);
+
+ brave::TabViewGuest* new_guest = new_helper->guest();
+ // always attach first because detach disconnects the webview
+ old_guest->AttachGuest(new_guest->guest_instance_id());
+ old_guest->DetachGuest(false);
+}
+
+void TabHelper::TabDetachedAt(content::WebContents* contents, int index) {
+ if (contents != web_contents())
+ return;
+
+ OnBrowserRemoved(browser_);
+}
+
+void TabHelper::UpdateBrowser(Browser* browser) {
+ browser_ = browser;
+ browser_->tab_strip_model()->AddObserver(this);
}
void TabHelper::SetBrowser(Browser* browser) {
@@ -93,13 +183,16 @@ void TabHelper::SetBrowser(Browser* browser) {
if (browser_) {
if (index_ != TabStripModel::kNoTab)
browser_->tab_strip_model()->DetachWebContentsAt(index_);
- }
- if (!browser)
- return;
+ OnBrowserRemoved(browser_);
+ }
- browser_ = browser;
- browser_->tab_strip_model()->AppendWebContents(web_contents(), false);
+ if (browser) {
+ UpdateBrowser(browser);
+ browser_->tab_strip_model()->AppendWebContents(web_contents(), false);
+ } else {
+ browser_ = nullptr;
+ }
}
void TabHelper::SetWindowId(const int32_t& id) {
@@ -119,10 +212,11 @@ void TabHelper::SetAutoDiscardable(bool auto_discardable) {
bool TabHelper::Discard() {
int64_t web_contents_id = TabManager::IdFromWebContents(web_contents());
- if (g_browser_process->GetTabManager()->DiscardTabById(web_contents_id))
- return true;
+ return !!g_browser_process->GetTabManager()->DiscardTabById(web_contents_id);
+}
- return false;
+bool TabHelper::IsDiscarded() {
+ return g_browser_process->GetTabManager()->IsTabDiscarded(web_contents());
}
void TabHelper::SetPinned(bool pinned) {
@@ -142,6 +236,12 @@ bool TabHelper::is_active() const {
}
}
+brave::TabViewGuest* TabHelper::guest() const {
+ auto guest = brave::TabViewGuest::FromWebContents(web_contents());
+ DCHECK(guest);
+ return guest;
+}
+
void TabHelper::SetTabValues(const base::DictionaryValue& values) {
values_->MergeDictionary(&values);
}
diff --git a/atom/browser/extensions/tab_helper.h b/atom/browser/extensions/tab_helper.h
index a49dfb5ebb..ddcb938fd2 100644
--- a/atom/browser/extensions/tab_helper.h
+++ b/atom/browser/extensions/tab_helper.h
@@ -10,6 +10,8 @@
#include "base/macros.h"
#include "chrome/browser/ui/browser_list_observer.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
+#include "components/guest_view/browser/guest_view_manager.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "extensions/browser/extension_function_dispatcher.h"
@@ -22,6 +24,10 @@ namespace base {
class DictionaryValue;
}
+namespace brave {
+class TabViewGuest;
+}
+
namespace content {
class BrowserContext;
class RenderFrameHost;
@@ -42,6 +48,8 @@ extern const char kAudibleKey[];
extern const char kMutedKey[];
}
+using guest_view::GuestViewManager;
+
namespace extensions {
class Extension;
@@ -50,10 +58,19 @@ class Extension;
// window of the tab.
class TabHelper : public content::WebContentsObserver,
public content::WebContentsUserData,
- public chrome::BrowserListObserver {
+ public chrome::BrowserListObserver,
+ public TabStripModelObserver {
public:
~TabHelper() override;
+ static void CreateTab(content::WebContents* owner,
+ content::BrowserContext* browser_context,
+ const base::DictionaryValue& create_params,
+ const GuestViewManager::WebContentsCreatedCallback& callback);
+ static content::WebContents* CreateTab(content::WebContents* owner,
+ content::WebContents::CreateParams create_params);
+ static void DestroyTab(content::WebContents* tab);
+
// Identifier of the tab.
void SetTabId(content::RenderFrameHost* render_frame_host);
int32_t session_id() const;
@@ -72,6 +89,8 @@ class TabHelper : public content::WebContentsObserver,
bool Discard();
+ bool IsDiscarded();
+
void SetTabValues(const base::DictionaryValue& values);
base::DictionaryValue* getTabValues() {
return values_.get();
@@ -87,6 +106,8 @@ class TabHelper : public content::WebContentsObserver,
return browser_;
}
+ brave::TabViewGuest* guest() const;
+
int get_index() const { return index_; }
bool is_pinned() const { return pinned_; }
bool is_active() const;
@@ -112,7 +133,18 @@ class TabHelper : public content::WebContentsObserver,
explicit TabHelper(content::WebContents* contents);
friend class content::WebContentsUserData;
- void OnBrowserRemoved(Browser* browser);
+ void TabDetachedAt(content::WebContents* contents, int index) override;
+ void TabInsertedAt(TabStripModel* tab_strip_model,
+ content::WebContents* contents,
+ int index,
+ bool foreground) override;
+ void TabReplacedAt(TabStripModel* tab_strip_model,
+ content::WebContents* old_contents,
+ content::WebContents* new_contents,
+ int index) override;
+ void OnBrowserRemoved(Browser* browser) override;
+ void UpdateBrowser(Browser* browser);
+
void ExecuteScript(
std::string extension_id,
std::unique_ptr options,
diff --git a/atom/common/api/resources/guest_view_api_bindings.js b/atom/common/api/resources/guest_view_api_bindings.js
new file mode 100644
index 0000000000..7edff7196a
--- /dev/null
+++ b/atom/common/api/resources/guest_view_api_bindings.js
@@ -0,0 +1,12 @@
+// Copyright 2014 The Brave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This module implements the public-facing API functions for the tag.
+
+const GuestView = require('guestView').GuestView;
+
+GuestView.prototype.getState = function() {
+ var internal = privates(this).internal;
+ return internal.state
+}
diff --git a/atom/common/api/resources/web_view_api_bindings.js b/atom/common/api/resources/web_view_api_bindings.js
index d1813e730e..737ff36434 100644
--- a/atom/common/api/resources/web_view_api_bindings.js
+++ b/atom/common/api/resources/web_view_api_bindings.js
@@ -8,7 +8,10 @@ const GuestViewInternal = require('guest-view-internal').GuestViewInternal
const TabViewInternal = require('tabViewInternal').TabViewInternal;
const WebViewInternal = require('webViewInternal').WebViewInternal;
const WebViewImpl = require('webView').WebViewImpl;
+const GuestViewImpl = require('guestView').GuestViewImpl
const remote = require('remote')
+const GuestViewContainer = require('guestViewContainer').GuestViewContainer;
+const GuestView = require('guestView').GuestView;
const asyncMethods = [
'loadURL',
@@ -62,14 +65,14 @@ const syncMethods = [
'getCurrentEntryIndex',
'getURLAtIndex',
'getTitleAtIndex',
- 'getId',
'isFocused',
'getZoomPercent',
'getURL',
]
var WEB_VIEW_API_METHODS = [
- 'setGuestInstanceId',
+ 'attachGuest',
+ 'detachGuest',
// Returns Chrome's internal process ID for the guest web page's current
// process.
'getProcessId',
@@ -77,12 +80,10 @@ var WEB_VIEW_API_METHODS = [
asyncMethods.forEach((method) => {
WebViewImpl.prototype[method] = function () {
- if (!this.guest.getId())
+ if (!this.tabID)
return
- this.getTabID(this.guest.getId(), (tabID) => {
- remote.callAsyncWebContentsFunction(tabID, method, arguments)
- })
+ remote.callAsyncWebContentsFunction(this.tabID, method, arguments)
}
})
@@ -101,46 +102,61 @@ syncMethods.forEach((method) => {
// -----------------------------------------------------------------------------
// Custom API method implementations.
-WebViewImpl.prototype.getTabID = function (instanceId, cb) {
- if (!this.tabID) {
- TabViewInternal.getTabID(instanceId, (tabID) => {
- this.tabID = tabID
- cb(tabID)
- })
- } else {
- cb(this.tabID)
- }
-}
-
const attachWindow = WebViewImpl.prototype.attachWindow$
-WebViewImpl.prototype.attachWindow$ = function(opt_guestInstanceId) {
- let attached = attachWindow.bind(this)(opt_guestInstanceId)
- // preload the webcontents and tabID
+WebViewImpl.prototype.attachWindow$ = function (opt_guestInstanceId) {
+ console.log('attachWindow ' + opt_guestInstanceId)
+ if (this.guest.getId() === opt_guestInstanceId &&
+ this.guest.getState() === GuestViewImpl.GuestState.GUEST_STATE_ATTACHED) {
+ return
+ }
const guestInstanceId = opt_guestInstanceId || this.guest.getId()
- WebViewInternal.getWebContents(guestInstanceId, (webContents) => {
- // cache webContents_
- this.webContents_ = webContents
- })
- this.getTabID(guestInstanceId, (tabID) => {
- // cache tabId
- this.tabID = tabID
- GuestViewInternal.registerEvents(this, tabID)
- })
+ if (opt_guestInstanceId || this.guest.getState() === GuestViewImpl.GuestState.GUEST_STATE_ATTACHED) {
+ this.guest.detach();
+ this.guest = new GuestView('webview', guestInstanceId);
+ }
+
+ const attached = GuestViewContainer.prototype.attachWindow$.call(this);
+ if (attached) {
+ WebViewInternal.getWebContents(guestInstanceId, (webContents) => {
+ // cache webContents_
+ this.webContents_ = webContents
+ })
+ }
return attached
}
-WebViewImpl.prototype.setGuestInstanceId = function (guestInstanceId) {
- return this.attachWindow$(guestInstanceId)
+WebViewImpl.prototype.detachGuest = function () {
+ const newGuest = () => {
+ this.guest = new GuestView('webview')
+ }
+ if (this.guest.getState() === GuestViewImpl.GuestState.GUEST_STATE_ATTACHED) {
+ this.guest.detach(() => newGuest())
+ } else {
+ newGuest()
+ }
}
WebViewImpl.prototype.getProcessId = function() {
return this.processId
}
+WebViewImpl.prototype.attachGuest = function (guestInstanceId) {
+ return this.attachWindow$(guestInstanceId)
+}
+
+WebViewImpl.prototype.setTabId = function (tabID) {
+ this.tabID = tabID
+ GuestViewInternal.registerEvents(this, tabID)
+}
+
+WebViewImpl.prototype.getId = function() {
+ return this.tabID
+}
+
// -----------------------------------------------------------------------------
-WebViewImpl.getApiMethods = function() {
+WebViewImpl.getApiMethods = function () {
return WEB_VIEW_API_METHODS;
};
diff --git a/atom/common/api/resources/web_view_events_api_bindings.js b/atom/common/api/resources/web_view_events_api_bindings.js
new file mode 100644
index 0000000000..2996e5b615
--- /dev/null
+++ b/atom/common/api/resources/web_view_events_api_bindings.js
@@ -0,0 +1,38 @@
+// Copyright 2014 The Brave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This module implements the public-facing API functions for the tag.
+
+const WebViewEvents = require('webViewEvents').WebViewEvents;
+const CreateEvent = require('guestViewEvents').CreateEvent;
+
+WebViewEvents.EVENTS['detachguest'] = {
+ evt: CreateEvent('webViewInternal.onDetachGuest'),
+ fields: [],
+ handler: 'handleDetachGuest',
+}
+
+WebViewEvents.EVENTS['attachguest'] = {
+ evt: CreateEvent('webViewInternal.onAttachGuest'),
+ fields: ['guestInstanceId'],
+ handler: 'handleAttachGuest'
+}
+
+WebViewEvents.EVENTS['tabidchanged'] = {
+ evt: CreateEvent('webViewInternal.onTabIdChanged'),
+ fields: ['tabID'],
+ handler: 'handleTabIdChanged'
+}
+
+WebViewEvents.prototype.handleDetachGuest = function(event, eventName) {
+ this.view.detachGuest()
+}
+
+WebViewEvents.prototype.handleAttachGuest = function(event, eventName) {
+ this.view.attachGuest(event.guestInstanceId)
+}
+
+WebViewEvents.prototype.handleTabIdChanged = function(event, eventName) {
+ this.view.setTabId(event.tabID)
+}
diff --git a/brave/browser/BUILD.gn b/brave/browser/BUILD.gn
index f55f99c614..c88ac39d10 100644
--- a/brave/browser/BUILD.gn
+++ b/brave/browser/BUILD.gn
@@ -108,6 +108,21 @@ source_set("browser") {
}
}
+source_set("tab_manager") {
+ configs += [
+ "//electron/build:electron_config",
+ ]
+
+ sources = [
+ "memory/guest_tab_manager.cc",
+ "memory/guest_tab_manager.h",
+ ]
+
+ deps = [
+ "//electron/chromium_src:tab_manager"
+ ]
+}
+
source_set("component_updater_api") {
configs += [
"//electron/build:electron_config",
diff --git a/brave/browser/guest_view/tab_view/tab_view_guest.cc b/brave/browser/guest_view/tab_view/tab_view_guest.cc
index 3ddb861514..b77b26d93b 100644
--- a/brave/browser/guest_view/tab_view/tab_view_guest.cc
+++ b/brave/browser/guest_view/tab_view/tab_view_guest.cc
@@ -63,8 +63,15 @@ GuestViewBase* TabViewGuest::Create(WebContents* owner_web_contents) {
// static
const char TabViewGuest::Type[] = "webview";
+void TabViewGuest::SetCanRunInDetachedState(bool can_run_detached) {
+ can_run_detached_ = can_run_detached;
+ if (!can_run_detached_ && !attached()) {
+ Destroy();
+ }
+}
+
bool TabViewGuest::CanRunInDetachedState() const {
- return true;
+ return can_run_detached_;
}
void TabViewGuest::GuestDestroyed() {
@@ -181,6 +188,25 @@ void TabViewGuest::DidCommitProvisionalLoadForFrame(
// find_helper_.CancelAllFindSessions();
}
+void TabViewGuest::AttachGuest(int guestInstanceId) {
+ std::unique_ptr args(new base::DictionaryValue());
+ args->SetInteger("guestInstanceId", guestInstanceId);
+ DispatchEventToView(base::MakeUnique(
+ "webViewInternal.onAttachGuest", std::move(args)));
+}
+
+void TabViewGuest::DetachGuest(bool notify_view) {
+ if (notify_view) {
+ std::unique_ptr args(new base::DictionaryValue());
+ DispatchEventToView(base::MakeUnique(
+ "webViewInternal.onDetachGuest", std::move(args)));
+ }
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ api_web_contents_->Emit("did-detach",
+ extensions::TabHelper::IdForTab(web_contents()));
+#endif
+}
+
void TabViewGuest::DidInitialize(const base::DictionaryValue& create_params) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
@@ -268,24 +294,24 @@ void TabViewGuest::ApplyAttributes(const base::DictionaryValue& params) {
void TabViewGuest::DidAttachToEmbedder() {
DCHECK(api_web_contents_);
+ auto tab_helper = extensions::TabHelper::FromWebContents(web_contents());
api_web_contents_->ResumeLoadingCreatedWebContents();
web_contents()->WasHidden();
web_contents()->WasShown();
- ApplyAttributes(*attach_params());
+ if (!tab_helper->IsDiscarded()) {
+ ApplyAttributes(*attach_params());
- if (web_contents()->GetController().IsInitialNavigation()) {
- web_contents()->GetController().LoadIfNecessary();
+ if (web_contents()->GetController().IsInitialNavigation()) {
+ web_contents()->GetController().LoadIfNecessary();
+ }
+ } else {
+ web_contents()->WasHidden();
}
-#if BUILDFLAG(ENABLE_EXTENSIONS)
api_web_contents_->Emit("did-attach",
extensions::TabHelper::IdForTab(web_contents()));
-#else
- api_web_contents_->Emit("did-attach",
- web_contents()->GetRenderProcessHost()->GetID());
-#endif
}
bool TabViewGuest::ZoomPropagatesFromEmbedderToGuest() const {
@@ -310,6 +336,11 @@ void TabViewGuest::GuestReady() {
->GetWidget()
->GetView()
->SetBackgroundColorToDefault();
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ api_web_contents_->Emit("guest-ready",
+ extensions::TabHelper::IdForTab(web_contents()), guest_instance_id());
+#endif
}
void TabViewGuest::WillDestroy() {
@@ -336,7 +367,8 @@ bool TabViewGuest::IsAutoSizeSupported() const {
TabViewGuest::TabViewGuest(WebContents* owner_web_contents)
: GuestView(owner_web_contents),
api_web_contents_(nullptr),
- clone_(false) {
+ clone_(false),
+ can_run_detached_(true) {
}
TabViewGuest::~TabViewGuest() {
@@ -353,8 +385,20 @@ void TabViewGuest::WillAttachToEmbedder() {
if (relay)
owner_window = relay->window.get();
- if (owner_window)
+ if (owner_window) {
+ std::unique_ptr args(new base::DictionaryValue());
+ args->SetInteger("tabID",
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ extensions::TabHelper::IdForTab(web_contents())
+#else
+ -1
+#endif
+ );
+ DispatchEventToView(base::MakeUnique(
+ "webViewInternal.onTabIdChanged", std::move(args)));
+
api_web_contents_->SetOwnerWindow(web_contents(), owner_window);
+ }
}
} // namespace brave
diff --git a/brave/browser/guest_view/tab_view/tab_view_guest.h b/brave/browser/guest_view/tab_view/tab_view_guest.h
index 2775e585e8..667b4a0e2c 100644
--- a/brave/browser/guest_view/tab_view/tab_view_guest.h
+++ b/brave/browser/guest_view/tab_view/tab_view_guest.h
@@ -27,6 +27,10 @@ class TabViewGuest : public guest_view::GuestView {
static const char Type[];
+ void AttachGuest(int guest_instance_id);
+ void DetachGuest(bool notify_view = true);
+ void SetCanRunInDetachedState(bool can_run_detached);
+
private:
explicit TabViewGuest(content::WebContents* owner_web_contents);
@@ -80,6 +84,7 @@ class TabViewGuest : public guest_view::GuestView {
bool clone_;
+ bool can_run_detached_;
// Stores the src URL of the WebView.
GURL src_;
diff --git a/brave/browser/memory/guest_tab_manager.cc b/brave/browser/memory/guest_tab_manager.cc
new file mode 100644
index 0000000000..f6eee68303
--- /dev/null
+++ b/brave/browser/memory/guest_tab_manager.cc
@@ -0,0 +1,51 @@
+// Copyright 2017 The Brave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "brave/browser/memory/guest_tab_manager.h"
+
+#include "atom/browser/extensions/tab_helper.h"
+#include "brave/browser/guest_view/tab_view/tab_view_guest.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "content/public/browser/web_contents.h"
+
+using content::WebContents;
+
+namespace memory {
+
+GuestTabManager::GuestTabManager() : TabManager() {}
+
+WebContents* GuestTabManager::CreateNullContents(
+ TabStripModel* model, WebContents* old_contents) {
+ auto tab_helper = extensions::TabHelper::FromWebContents(old_contents);
+ DCHECK(tab_helper && tab_helper->guest());
+
+ auto embedder = tab_helper->guest()->embedder_web_contents();
+
+ return extensions::TabHelper::CreateTab(embedder,
+ WebContents::CreateParams(old_contents->GetBrowserContext()));
+}
+
+void GuestTabManager::DestroyOldContents(WebContents* old_contents) {
+ auto tab_helper = extensions::TabHelper::FromWebContents(old_contents);
+ DCHECK(tab_helper && tab_helper->guest());
+ // Let the guest destroy itself after the detach message has been received
+ tab_helper->guest()->SetCanRunInDetachedState(false);
+}
+
+void GuestTabManager::ActiveTabChanged(content::WebContents* old_contents,
+ content::WebContents* new_contents,
+ int index,
+ int reason) {
+ bool discarded = IsTabDiscarded(new_contents);
+ TabManager::ActiveTabChanged(old_contents, new_contents, index, reason);
+ if (discarded) {
+ if (reason == TabStripModelObserver::CHANGE_REASON_USER_GESTURE)
+ new_contents->UserGestureDone();
+
+ new_contents->GetController().Reload(content::ReloadType::NORMAL, true);
+ }
+}
+
+} // namespace
diff --git a/brave/browser/memory/guest_tab_manager.h b/brave/browser/memory/guest_tab_manager.h
new file mode 100644
index 0000000000..e6705b09ab
--- /dev/null
+++ b/brave/browser/memory/guest_tab_manager.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2017 The Brave Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BRAVE_BROWSER_MEMORY_GUEST_TAB_MANAGER_H_
+#define BRAVE_BROWSER_MEMORY_GUEST_TAB_MANAGER_H_
+
+#include "chrome/browser/memory/tab_manager.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace memory {
+
+class GuestTabManager : public TabManager {
+ public:
+ GuestTabManager();
+
+ private:
+ void ActiveTabChanged(content::WebContents* old_contents,
+ content::WebContents* new_contents,
+ int index,
+ int reason) override;
+ // MUON(bridiver): override to create/destroy guests webcontents
+ virtual content::WebContents* CreateNullContents(
+ TabStripModel* model, content::WebContents* old_contents);
+ virtual void DestroyOldContents(content::WebContents* old_contents);
+
+ DISALLOW_COPY_AND_ASSIGN(GuestTabManager);
+};
+
+} // namespace memory
+
+#endif // BRAVE_BROWSER_MEMORY_GUEST_T#include "chrome/browser/memory/tab_manager.h
diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn
index b065c35075..db12a4ad67 100644
--- a/chromium_src/BUILD.gn
+++ b/chromium_src/BUILD.gn
@@ -131,7 +131,7 @@ source_set("browser") {
":devtools",
":importer",
":sessions",
- ":tab_manager",
+ "//electron/brave/browser:tab_manager",
"//chrome/common",
"//chrome/utility",
"//components/certificate_transparency",
diff --git a/chromium_src/chrome/browser/browser_process_impl.cc b/chromium_src/chrome/browser/browser_process_impl.cc
index d56c29e704..c2b1d2a5f7 100644
--- a/chromium_src/chrome/browser/browser_process_impl.cc
+++ b/chromium_src/chrome/browser/browser_process_impl.cc
@@ -14,10 +14,10 @@
#include "base/threading/thread_restrictions.h"
#include "brave/browser/brave_content_browser_client.h"
#include "brave/browser/component_updater/brave_component_updater_configurator.h"
+#include "brave/browser/memory/guest_tab_manager.h"
#include "brightray/browser/brightray_paths.h"
#include "chrome/browser/background/background_mode_manager.h"
#include "chrome/browser/browser_shutdown.h"
-#include "chrome/browser/memory/tab_manager.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/shell_integration.h"
@@ -252,7 +252,7 @@ memory::TabManager* BrowserProcessImpl::GetTabManager() {
DCHECK(thread_checker_.CalledOnValidThread());
#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
if (!tab_manager_.get())
- tab_manager_.reset(new memory::TabManager());
+ tab_manager_.reset(new memory::GuestTabManager());
return tab_manager_.get();
#else
return nullptr;
diff --git a/chromium_src/chrome/browser/ui/tabs/tab_strip_model.cc b/chromium_src/chrome/browser/ui/tabs/tab_strip_model.cc
index a631b0496b..8d8d22476a 100644
--- a/chromium_src/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chromium_src/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -82,7 +82,9 @@ void TabStripModel::AppendWebContents(WebContents* contents,
base::MakeUnique(contents);
// the TabHelper tracks the actual index for now
- int index = tab_helper->get_index() || contents_data_.size() - 1;
+ int index = tab_helper->get_index() != kNoTab
+ ? tab_helper->get_index()
+ : contents_data_.size();
contents_data_.push_back(std::move(data));
for (auto& observer : observers_)
observer.TabInsertedAt(this, contents, index, foreground);
@@ -96,7 +98,7 @@ WebContents* TabStripModel::ReplaceWebContentsAt(int index,
WebContents* old_contents = GetWebContentsAt(index);
for (size_t i = 0; i < contents_data_.size(); ++i) {
- if (contents_data_[i]->tab_helper()->get_index() == index) {
+ if (contents_data_[i]->web_contents() == old_contents) {
contents_data_[i]->SetWebContents(new_contents);
break;
}
@@ -126,8 +128,8 @@ WebContents* TabStripModel::DetachWebContentsAt(int index) {
WebContents* removed_contents = GetWebContentsAt(index);
for (size_t i = 0; i < contents_data_.size(); ++i) {
- if (contents_data_[i]->tab_helper()->get_index() == index) {
- contents_data_.erase(contents_data_.begin() + index);
+ if (contents_data_[i]->web_contents() == removed_contents) {
+ contents_data_.erase(contents_data_.begin() + i);
break;
}
}
@@ -159,16 +161,21 @@ WebContents* TabStripModel::GetActiveWebContents() const {
WebContents* TabStripModel::GetWebContentsAt(int index) const {
for (size_t i = 0; i < contents_data_.size(); ++i) {
- if (contents_data_[i]->tab_helper()->get_index() == index)
+ auto tab_helper = contents_data_[i]->tab_helper();
+ if (tab_helper && tab_helper->get_index() == index)
return contents_data_[i]->web_contents();
}
return nullptr;
}
int TabStripModel::GetIndexOfWebContents(const WebContents* contents) const {
- auto tab_helper = TabHelper::FromWebContents(contents);
- if (tab_helper)
- return tab_helper->get_index();
+ for (size_t i = 0; i < contents_data_.size(); ++i) {
+ // make sure the webcontents is in this tab strip model
+ if (contents == contents_data_[i]->web_contents() &&
+ contents_data_[i]->tab_helper()) {
+ return contents_data_[i]->tab_helper()->get_index();
+ }
+ }
return kNoTab;
}
diff --git a/chromium_src/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc b/chromium_src/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
index 8114e01ae4..c17d2d3997 100644
--- a/chromium_src/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
+++ b/chromium_src/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
@@ -210,6 +210,10 @@ void ChromeExtensionsDispatcherDelegate::PopulateSourceMap(
IDR_ATOM_TAB_VIEW_INTERNAL_BINDINGS_JS);
source_map->RegisterSource("webViewApiMethods",
IDR_ATOM_WEB_VIEW_API_BINDINGS_JS);
+ source_map->RegisterSource("webViewEventsApiMethods",
+ IDR_ATOM_WEB_VIEW_EVENTS_API_BINDINGS_JS);
+ source_map->RegisterSource("guestViewApiMethods",
+ IDR_ATOM_GUEST_VIEW_API_BINDINGS_JS);
}
void ChromeExtensionsDispatcherDelegate::RequireAdditionalModules(
@@ -223,6 +227,8 @@ void ChromeExtensionsDispatcherDelegate::RequireAdditionalModules(
module_system->Require("webViewInternal");
module_system->Require("webViewApiMethods");
module_system->Require("webViewAttributes");
+ module_system->Require("webViewEventsApiMethods");
+ module_system->Require("guestViewApiMethods");
}
if (context_type == extensions::Feature::WEBUI_CONTEXT ||
diff --git a/lib/browser/guest-view-manager.js b/lib/browser/guest-view-manager.js
index 08e1b3f905..3b6e0e2541 100644
--- a/lib/browser/guest-view-manager.js
+++ b/lib/browser/guest-view-manager.js
@@ -7,6 +7,7 @@ let supportedWebViewEvents = [
'load-start',
'load-commit',
'did-attach',
+ 'guest-ready',
'did-detach',
'did-finish-load',
'did-fail-provisional-load',
@@ -68,18 +69,21 @@ const registerGuest = function (guest, embedder) {
return
}
- guest.once('destroyed', function () {
- delete guests[tabId]
- })
- guest.once('crashed', function () {
- delete guests[tabId]
- })
-
// Dispatch events to embedder.
const fn = function (event) {
guest.on(event, function (_, ...args) {
const embedder = guests[tabId]
- if (!embedder || embedder.isDestroyed() || guest.isDestroyed())
+
+ if (!embedder || embedder.isDestroyed())
+ return
+
+ let forceSend = false
+ if (['destroyed', 'crashed', 'did-detach'].includes(event)) {
+ delete guests[tabId]
+ forceSend = true
+ }
+
+ if (guest.isDestroyed() && !forceSend)
return
embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + tabId, event].concat(args))
diff --git a/lib/renderer/web-view/guest-view-internal.js b/lib/renderer/web-view/guest-view-internal.js
index b547a30c01..40e85a13ee 100644
--- a/lib/renderer/web-view/guest-view-internal.js
+++ b/lib/renderer/web-view/guest-view-internal.js
@@ -6,6 +6,7 @@ var WEB_VIEW_EVENTS = {
'load-start': ['url', 'isMainFrame', 'isErrorPage'],
'load-commit': ['url', 'isMainFrame'],
'did-attach': ['tabId'],
+ 'guest-ready': ['tabId', 'guestInstanceId'],
'did-detach': [],
'did-finish-load': ['validatedURL'],
'did-fail-provisional-load': ['errorCode', 'errorDescription', 'validatedURL', 'isMainFrame', 'currentURL'],
diff --git a/patches/master_patch.patch b/patches/master_patch.patch
index 04fbcab156..4eb1af148c 100644
--- a/patches/master_patch.patch
+++ b/patches/master_patch.patch
@@ -159,6 +159,82 @@ index b77fbdeea3cd28ead065828c3fffb19496f80ab8..86aad8c1312e801ff64a81b11700d3a4
return;
}
+diff --git a/chrome/browser/memory/tab_manager.cc b/chrome/browser/memory/tab_manager.cc
+index 6c2cf66a1aba3f71310e4e3317e849839d3b0e0b..af107629afbea2e9c13686765cace0e55c70c4f4 100644
+--- a/chrome/browser/memory/tab_manager.cc
++++ b/chrome/browser/memory/tab_manager.cc
+@@ -786,6 +786,17 @@ void TabManager::PurgeAndSuspendBackgroundedTabs() {
+ }
+ }
+
++// MUON(bridiver): see tab_manager.h
++WebContents* TabManager::CreateNullContents(
++ TabStripModel* model, WebContents* old_contents) {
++ return WebContents::Create(WebContents::CreateParams(model->profile()));
++}
++
++// MUON(bridiver): see tab_manager.h
++void TabManager::DestroyOldContents(WebContents* old_contents) {
++ delete old_contents;
++}
++
+ WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) {
+ // Can't discard active index.
+ if (model->active_index() == index)
+@@ -805,8 +816,8 @@ WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) {
+ "TabManager.Discarding.DiscardedTabHasBeforeUnloadHandler",
+ old_contents->NeedToFireBeforeUnload());
+
+- WebContents* null_contents =
+- WebContents::Create(WebContents::CreateParams(model->profile()));
++ // MUON(bridiver): see tab_manager.h
++ WebContents* null_contents = CreateNullContents(model, old_contents);
+ // Copy over the state from the navigation controller to preserve the
+ // back/forward history and to continue to display the correct title/favicon.
+ null_contents->GetController().CopyStateFrom(old_contents->GetController());
+@@ -818,7 +829,7 @@ WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) {
+
+ // Replace the discarded tab with the null version.
+ model->ReplaceWebContentsAt(index, null_contents);
+- // Mark the tab so it will reload when clicked on.
++ // Mark the tab so it will reload when clicked on
+ GetWebContentsData(null_contents)->SetDiscardState(true);
+ GetWebContentsData(null_contents)->IncrementDiscardCount();
+
+@@ -826,7 +837,8 @@ WebContents* TabManager::DiscardWebContentsAt(int index, TabStripModel* model) {
+ // TODO(jamescook): This breaks script connections with other tabs.
+ // Find a different approach that doesn't do that, perhaps based on navigation
+ // to swappedout://.
+- delete old_contents;
++ // MUON(bridiver): see tab_manager.h
++ DestroyOldContents(old_contents);
+ recent_tab_discard_ = true;
+
+ return null_contents;
+diff --git a/chrome/browser/memory/tab_manager.h b/chrome/browser/memory/tab_manager.h
+index 55b6d1d98314f0adcdd087b0c64379b453df24e5..4c72b67644434ed82e94c94dea57f8dffd5cf4a4 100644
+--- a/chrome/browser/memory/tab_manager.h
++++ b/chrome/browser/memory/tab_manager.h
+@@ -181,6 +181,7 @@ class TabManager : public TabStripModelObserver {
+ // This is needed so WebContentsData can call OnDiscardedStateChange, and
+ // can use PurgeAndSuspendState.
+ friend class WebContentsData;
++ friend class GuestTabManager;
+
+ // Called by WebContentsData whenever the discard state of a WebContents
+ // changes, so that observers can be informed.
+@@ -331,6 +332,11 @@ class TabManager : public TabStripModelObserver {
+ // Returns true if tabs can be discarded only once.
+ bool CanOnlyDiscardOnce();
+
++ // MUON(bridiver): override to create/destroy guests webcontents
++ virtual content::WebContents* CreateNullContents(
++ TabStripModel* model, content::WebContents* old_contents);
++ virtual void DestroyOldContents(content::WebContents* old_contents);
++
+ // Timer to periodically update the stats of the renderers.
+ base::RepeatingTimer update_timer_;
+
diff --git a/chrome/browser/plugins/chrome_plugin_service_filter.cc b/chrome/browser/plugins/chrome_plugin_service_filter.cc
index 1783a101aa024a5aa39a7bd7c335427398d47093..ac11311d78e2271f9ca7f6016c79a37de078621c 100644
--- a/chrome/browser/plugins/chrome_plugin_service_filter.cc
@@ -2259,6 +2335,21 @@ index 00a8accbe2cdc3c77c6fce3fd28cd697ff0524d5..8a9cf6907b0d27cb5b1a7fd8eed00500
#else
is_elastic_overscroll_enabled_ = false;
#endif
+diff --git a/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc b/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc
+index 061480b5acd6431aa9abb7e02c98ebe5e881d7f9..cb06be194f24f5b7865874101da696b8f168c3ab 100644
+--- a/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc
++++ b/extensions/browser/guest_view/extensions_guest_view_manager_delegate.cc
+@@ -53,8 +53,8 @@ void ExtensionsGuestViewManagerDelegate::DispatchEvent(
+ // extensions::events::HistogramValue as an argument.
+ events::HistogramValue histogram_value =
+ guest_view_events::GetEventHistogramValue(event_name);
+- DCHECK_NE(events::UNKNOWN, histogram_value) << "Event " << event_name
+- << " must have a histogram value";
++ // DCHECK_NE(events::UNKNOWN, histogram_value) << "Event " << event_name
++ // << " must have a histogram value";
+
+ content::WebContents* owner = guest->owner_web_contents();
+ if (!owner)
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 57c9a2e6a43558e2325a76b5b147a3c7e2b99fd3..5ee029882c5ecf0104f83ee61e4a0ba729a7a516 100644
--- a/extensions/common/api/_api_features.json
@@ -2278,6 +2369,7 @@ index 57c9a2e6a43558e2325a76b5b147a3c7e2b99fd3..5ee029882c5ecf0104f83ee61e4a0ba7
@@ -510,6 +513,7 @@
"internal": true,
"contexts": ["webui"],
++ // MUON(bridiver): creating new histograms is a pain
"matches": [
+ "chrome://brave/*",
"chrome://chrome-signin/*",