fix: prevent destroyed view references from causing crashes (#25511)

This commit is contained in:
trop[bot]
2020-09-24 11:26:58 -07:00
committed by GitHub
parent 6fe6dffe93
commit e964c1ed7b
9 changed files with 125 additions and 37 deletions

View File

@@ -751,8 +751,10 @@ void TopLevelWindow::AddBrowserView(v8::Local<v8::Value> value) {
gin::ConvertFromV8(isolate(), value, &browser_view)) {
auto get_that_view = browser_views_.find(browser_view->weak_map_id());
if (get_that_view == browser_views_.end()) {
window_->AddBrowserView(browser_view->view());
browser_view->web_contents()->SetOwnerWindow(window_.get());
if (browser_view->web_contents()) {
window_->AddBrowserView(browser_view->view());
browser_view->web_contents()->SetOwnerWindow(window_.get());
}
browser_views_[browser_view->weak_map_id()].Reset(isolate(), value);
}
}
@@ -764,9 +766,10 @@ void TopLevelWindow::RemoveBrowserView(v8::Local<v8::Value> value) {
gin::ConvertFromV8(isolate(), value, &browser_view)) {
auto get_that_view = browser_views_.find(browser_view->weak_map_id());
if (get_that_view != browser_views_.end()) {
window_->RemoveBrowserView(browser_view->view());
browser_view->web_contents()->SetOwnerWindow(nullptr);
if (browser_view->web_contents()) {
window_->RemoveBrowserView(browser_view->view());
browser_view->web_contents()->SetOwnerWindow(nullptr);
}
(*get_that_view).second.Reset(isolate(), value);
browser_views_.erase(get_that_view);
}
@@ -1064,8 +1067,10 @@ void TopLevelWindow::ResetBrowserViews() {
v8::Local<v8::Value>::New(isolate(), item.second),
&browser_view) &&
!browser_view.IsEmpty()) {
window_->RemoveBrowserView(browser_view->view());
browser_view->web_contents()->SetOwnerWindow(nullptr);
if (browser_view->web_contents()) {
window_->RemoveBrowserView(browser_view->view());
browser_view->web_contents()->SetOwnerWindow(nullptr);
}
}
item.second.Reset();

View File

@@ -700,7 +700,8 @@ WebContents::~WebContents() {
} else {
// Destroy WebContents asynchronously unless app is shutting down,
// because destroy() might be called inside WebContents's event handler.
DestroyWebContents(!IsGuest() /* async */);
bool is_browser_view = type_ == Type::BROWSER_VIEW;
DestroyWebContents(!(IsGuest() || is_browser_view) /* async */);
// The WebContentsDestroyed will not be called automatically because we
// destroy the webContents in the next tick. So we have to manually
// call it here to make sure "destroyed" event is emitted.

View File

@@ -13,16 +13,26 @@ namespace electron {
NativeBrowserView::NativeBrowserView(
InspectableWebContents* inspectable_web_contents)
: inspectable_web_contents_(inspectable_web_contents) {}
: inspectable_web_contents_(inspectable_web_contents) {
Observe(inspectable_web_contents_->GetWebContents());
}
NativeBrowserView::~NativeBrowserView() = default;
InspectableWebContentsView* NativeBrowserView::GetInspectableWebContentsView() {
if (!inspectable_web_contents_)
return nullptr;
return inspectable_web_contents_->GetView();
}
content::WebContents* NativeBrowserView::GetWebContents() {
if (!inspectable_web_contents_)
return nullptr;
return inspectable_web_contents_->GetWebContents();
}
void NativeBrowserView::WebContentsDestroyed() {
inspectable_web_contents_ = nullptr;
}
} // namespace electron

View File

@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/skia/include/core/SkColor.h"
namespace gfx {
@@ -27,9 +28,9 @@ enum AutoResizeFlags {
class InspectableWebContents;
class InspectableWebContentsView;
class NativeBrowserView {
class NativeBrowserView : public content::WebContentsObserver {
public:
virtual ~NativeBrowserView();
~NativeBrowserView() override;
static NativeBrowserView* Create(
InspectableWebContents* inspectable_web_contents);
@@ -52,6 +53,8 @@ class NativeBrowserView {
protected:
explicit NativeBrowserView(InspectableWebContents* inspectable_web_contents);
// content::WebContentsObserver:
void WebContentsDestroyed() override;
InspectableWebContents* inspectable_web_contents_;

View File

@@ -162,8 +162,10 @@ namespace electron {
NativeBrowserViewMac::NativeBrowserViewMac(
InspectableWebContents* inspectable_web_contents)
: NativeBrowserView(inspectable_web_contents) {
auto* view =
GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
auto* iwc_view = GetInspectableWebContentsView();
if (!iwc_view)
return;
auto* view = iwc_view->GetNativeView().GetNativeNSView();
view.autoresizingMask = kDefaultAutoResizingMask;
}
@@ -186,14 +188,18 @@ void NativeBrowserViewMac::SetAutoResizeFlags(uint8_t flags) {
NSViewMaxYMargin | NSViewMinYMargin | NSViewHeightSizable;
}
auto* view =
GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
auto* iwc_view = GetInspectableWebContentsView();
if (!iwc_view)
return;
auto* view = iwc_view->GetNativeView().GetNativeNSView();
view.autoresizingMask = autoresizing_mask;
}
void NativeBrowserViewMac::SetBounds(const gfx::Rect& bounds) {
auto* view =
GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
auto* iwc_view = GetInspectableWebContentsView();
if (!iwc_view)
return;
auto* view = iwc_view->GetNativeView().GetNativeNSView();
auto* superview = view.superview;
const auto superview_height = superview ? superview.frame.size.height : 0;
view.frame =
@@ -202,8 +208,10 @@ void NativeBrowserViewMac::SetBounds(const gfx::Rect& bounds) {
}
gfx::Rect NativeBrowserViewMac::GetBounds() {
NSView* view =
GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
auto* iwc_view = GetInspectableWebContentsView();
if (!iwc_view)
return gfx::Rect();
NSView* view = iwc_view->GetNativeView().GetNativeNSView();
const int superview_height =
(view.superview) ? view.superview.frame.size.height : 0;
return gfx::Rect(
@@ -213,17 +221,22 @@ gfx::Rect NativeBrowserViewMac::GetBounds() {
}
void NativeBrowserViewMac::SetBackgroundColor(SkColor color) {
auto* view =
GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
auto* iwc_view = GetInspectableWebContentsView();
if (!iwc_view)
return;
auto* view = iwc_view->GetNativeView().GetNativeNSView();
view.wantsLayer = YES;
view.layer.backgroundColor = skia::CGColorCreateFromSkColor(color);
}
void NativeBrowserViewMac::UpdateDraggableRegions(
const std::vector<gfx::Rect>& drag_exclude_rects) {
auto* iwc_view = GetInspectableWebContentsView();
auto* web_contents = GetWebContents();
if (!(iwc_view && web_contents))
return;
NSView* web_view = GetWebContents()->GetNativeView().GetNativeNSView();
NSView* inspectable_view =
GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
NSView* inspectable_view = iwc_view->GetNativeView().GetNativeNSView();
NSView* window_content_view = inspectable_view.superview;
const auto window_content_view_height = NSHeight(window_content_view.bounds);

View File

@@ -26,7 +26,10 @@ void NativeBrowserViewViews::SetAutoResizeProportions(
const gfx::Size& window_size) {
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeHorizontal) &&
!auto_horizontal_proportion_set_) {
auto* view = GetInspectableWebContentsView()->GetView();
auto* iwc_view = GetInspectableWebContentsView();
if (iwc_view)
return;
auto* view = iwc_view->GetView();
auto view_bounds = view->bounds();
auto_horizontal_proportion_width_ =
static_cast<float>(window_size.width()) /
@@ -37,7 +40,10 @@ void NativeBrowserViewViews::SetAutoResizeProportions(
}
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeVertical) &&
!auto_vertical_proportion_set_) {
auto* view = GetInspectableWebContentsView()->GetView();
auto* iwc_view = GetInspectableWebContentsView();
if (iwc_view)
return;
auto* view = iwc_view->GetView();
auto view_bounds = view->bounds();
auto_vertical_proportion_height_ =
static_cast<float>(window_size.height()) /
@@ -51,7 +57,10 @@ void NativeBrowserViewViews::SetAutoResizeProportions(
void NativeBrowserViewViews::AutoResize(const gfx::Rect& new_window,
int width_delta,
int height_delta) {
auto* view = GetInspectableWebContentsView()->GetView();
auto* iwc_view = GetInspectableWebContentsView();
if (iwc_view)
return;
auto* view = iwc_view->GetView();
const auto flags = GetAutoResizeFlags();
if (!(flags & kAutoResizeWidth)) {
width_delta = 0;
@@ -92,17 +101,26 @@ void NativeBrowserViewViews::ResetAutoResizeProportions() {
}
void NativeBrowserViewViews::SetBounds(const gfx::Rect& bounds) {
auto* view = GetInspectableWebContentsView()->GetView();
auto* iwc_view = GetInspectableWebContentsView();
if (!iwc_view)
return;
auto* view = iwc_view->GetView();
view->SetBoundsRect(bounds);
ResetAutoResizeProportions();
}
gfx::Rect NativeBrowserViewViews::GetBounds() {
return GetInspectableWebContentsView()->GetView()->bounds();
auto* iwc_view = GetInspectableWebContentsView();
if (!iwc_view)
return gfx::Rect();
return iwc_view->GetView()->bounds();
}
void NativeBrowserViewViews::SetBackgroundColor(SkColor color) {
auto* view = GetInspectableWebContentsView()->GetView();
auto* iwc_view = GetInspectableWebContentsView();
if (!iwc_view)
return;
auto* view = iwc_view->GetView();
view->SetBackground(views::CreateSolidBackground(color));
view->SchedulePaint();
}

View File

@@ -1270,8 +1270,11 @@ void NativeWindowMac::AddBrowserView(NativeBrowserView* view) {
}
add_browser_view(view);
auto* native_view =
view->GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();
auto* iwc_view = view->GetInspectableWebContentsView();
if (!iwc_view)
return;
auto* native_view = iwc_view->GetNativeView().GetNativeNSView();
[[window_ contentView] addSubview:native_view
positioned:NSWindowAbove
relativeTo:nil];
@@ -1289,8 +1292,11 @@ void NativeWindowMac::RemoveBrowserView(NativeBrowserView* view) {
return;
}
[view->GetInspectableWebContentsView()->GetNativeView().GetNativeNSView()
removeFromSuperview];
auto* iwc_view = view->GetInspectableWebContentsView();
if (!iwc_view)
return;
[iwc_view->GetNativeView().GetNativeNSView() removeFromSuperview];
remove_browser_view(view);
[CATransaction commit];

View File

@@ -1070,8 +1070,10 @@ void NativeWindowViews::AddBrowserView(NativeBrowserView* view) {
add_browser_view(view);
content_view()->AddChildView(
view->GetInspectableWebContentsView()->GetView());
auto* iwc_view = view->GetInspectableWebContentsView();
if (!iwc_view)
return;
content_view()->AddChildView(iwc_view->GetView());
}
void NativeWindowViews::RemoveBrowserView(NativeBrowserView* view) {
@@ -1082,8 +1084,11 @@ void NativeWindowViews::RemoveBrowserView(NativeBrowserView* view) {
return;
}
content_view()->RemoveChildView(
view->GetInspectableWebContentsView()->GetView());
auto* iwc_view = view->GetInspectableWebContentsView();
if (!iwc_view)
return;
content_view()->RemoveChildView(iwc_view->GetView());
remove_browser_view(view);
}

View File

@@ -0,0 +1,27 @@
const { app, BrowserWindow, BrowserView } = require('electron');
const { expect } = require('chai');
const assert = require('assert');
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
});
const view = new BrowserView();
mainWindow.addBrowserView(view);
view.webContents.destroy();
view.setBounds({ x: 0, y: 0, width: 0, height: 0 });
const bounds = view.getBounds();
expect(bounds).to.deep.equal({ x: 0, y: 0, width: 0, height: 0 });
view.setBackgroundColor('#56cc5b10');
}
app.on('ready', () => {
createWindow();
app.quit();
});