Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
// Copyright (c) 2017 GitHub, Inc.
|
|
|
|
// Use of this source code is governed by the MIT license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2019-06-19 20:46:59 +00:00
|
|
|
#include "shell/browser/native_browser_view_mac.h"
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
|
2021-02-08 17:14:46 +00:00
|
|
|
#import <objc/runtime.h>
|
2019-05-02 12:05:37 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2020-10-27 21:28:43 +00:00
|
|
|
#include "shell/browser/ui/drag_util.h"
|
2019-06-19 20:46:59 +00:00
|
|
|
#include "shell/browser/ui/inspectable_web_contents.h"
|
|
|
|
#include "shell/browser/ui/inspectable_web_contents_view.h"
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
#include "skia/ext/skia_utils_mac.h"
|
|
|
|
#include "ui/gfx/geometry/rect.h"
|
|
|
|
|
2017-04-12 11:40:31 +00:00
|
|
|
// Match view::Views behavior where the view sticks to the top-left origin.
|
|
|
|
const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
|
|
|
|
NSViewMaxXMargin | NSViewMinYMargin;
|
|
|
|
|
2017-08-09 00:00:00 +00:00
|
|
|
@interface DragRegionView : NSView
|
2017-08-09 18:57:57 +00:00
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
@property(assign) NSPoint initialLocation;
|
2017-08-09 18:57:57 +00:00
|
|
|
|
2017-08-09 00:00:00 +00:00
|
|
|
@end
|
|
|
|
|
2017-08-23 23:10:31 +00:00
|
|
|
@interface NSWindow ()
|
2018-04-20 18:47:04 +00:00
|
|
|
- (void)performWindowDragWithEvent:(NSEvent*)event;
|
2017-08-23 23:10:31 +00:00
|
|
|
@end
|
|
|
|
|
2017-08-09 00:00:00 +00:00
|
|
|
@implementation DragRegionView
|
|
|
|
|
2018-04-17 23:46:33 +00:00
|
|
|
@synthesize initialLocation;
|
|
|
|
|
2021-02-08 17:14:46 +00:00
|
|
|
+ (void)load {
|
|
|
|
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
|
|
|
|
static dispatch_once_t onceToken;
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
SEL originalSelector = @selector(drawRect:);
|
|
|
|
SEL swizzledSelector = @selector(drawDebugRect:);
|
|
|
|
|
|
|
|
Method originalMethod =
|
|
|
|
class_getInstanceMethod([self class], originalSelector);
|
|
|
|
Method swizzledMethod =
|
|
|
|
class_getInstanceMethod([self class], swizzledSelector);
|
|
|
|
BOOL didAddMethod =
|
|
|
|
class_addMethod([self class], originalSelector,
|
|
|
|
method_getImplementation(swizzledMethod),
|
|
|
|
method_getTypeEncoding(swizzledMethod));
|
|
|
|
|
|
|
|
if (didAddMethod) {
|
|
|
|
class_replaceMethod([self class], swizzledSelector,
|
|
|
|
method_getImplementation(originalMethod),
|
|
|
|
method_getTypeEncoding(originalMethod));
|
|
|
|
} else {
|
|
|
|
method_exchangeImplementations(originalMethod, swizzledMethod);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
- (BOOL)mouseDownCanMoveWindow {
|
2021-09-28 19:12:22 +00:00
|
|
|
return
|
|
|
|
[self.window respondsToSelector:@selector(performWindowDragWithEvent:)];
|
2017-08-09 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2021-09-23 21:35:12 +00:00
|
|
|
- (BOOL)acceptsFirstMouse:(NSEvent*)event {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2020-11-17 04:41:37 +00:00
|
|
|
- (BOOL)shouldIgnoreMouseEvent {
|
|
|
|
NSEventType type = [[NSApp currentEvent] type];
|
|
|
|
return type != NSEventTypeLeftMouseDragged &&
|
|
|
|
type != NSEventTypeLeftMouseDown;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSView*)hitTest:(NSPoint)point {
|
|
|
|
// Pass-through events that hit one of the exclusion zones
|
2020-10-27 21:28:43 +00:00
|
|
|
for (NSView* exclusion_zones in [self subviews]) {
|
2020-11-17 04:41:37 +00:00
|
|
|
if ([exclusion_zones hitTest:point])
|
2018-04-20 18:47:04 +00:00
|
|
|
return nil;
|
|
|
|
}
|
2017-08-09 21:49:11 +00:00
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
return self;
|
2017-08-09 21:49:11 +00:00
|
|
|
}
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
- (void)mouseDown:(NSEvent*)event {
|
2020-11-17 04:41:37 +00:00
|
|
|
[super mouseDown:event];
|
|
|
|
|
2021-09-28 19:12:22 +00:00
|
|
|
if ([self.window respondsToSelector:@selector(performWindowDragWithEvent:)]) {
|
2017-09-29 18:20:34 +00:00
|
|
|
// According to Google, using performWindowDragWithEvent:
|
|
|
|
// does not generate a NSWindowWillMoveNotification. Hence post one.
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
postNotificationName:NSWindowWillMoveNotification
|
|
|
|
object:self];
|
|
|
|
|
2021-09-28 19:12:22 +00:00
|
|
|
[self.window performWindowDragWithEvent:event];
|
|
|
|
|
2017-08-09 18:57:57 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-26 23:00:57 +00:00
|
|
|
if (self.window.styleMask & NSWindowStyleMaskFullScreen) {
|
2017-09-26 22:03:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-09 18:57:57 +00:00
|
|
|
self.initialLocation = [event locationInWindow];
|
|
|
|
}
|
|
|
|
|
2020-11-17 04:41:37 +00:00
|
|
|
- (void)mouseDragged:(NSEvent*)event {
|
2021-09-28 19:12:22 +00:00
|
|
|
if ([self.window respondsToSelector:@selector(performWindowDragWithEvent:)]) {
|
2017-08-09 18:57:57 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-09-26 22:03:44 +00:00
|
|
|
|
2018-09-26 23:00:57 +00:00
|
|
|
if (self.window.styleMask & NSWindowStyleMaskFullScreen) {
|
2017-09-26 22:03:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-08-09 18:57:57 +00:00
|
|
|
|
2017-08-15 23:13:14 +00:00
|
|
|
NSPoint currentLocation = [NSEvent mouseLocation];
|
2017-08-09 18:57:57 +00:00
|
|
|
NSPoint newOrigin;
|
|
|
|
|
|
|
|
NSRect screenFrame = [[NSScreen mainScreen] frame];
|
2017-09-27 21:43:09 +00:00
|
|
|
NSSize screenSize = screenFrame.size;
|
2017-08-09 18:57:57 +00:00
|
|
|
NSRect windowFrame = [self.window frame];
|
2017-09-27 21:43:09 +00:00
|
|
|
NSSize windowSize = windowFrame.size;
|
2017-08-09 18:57:57 +00:00
|
|
|
|
|
|
|
newOrigin.x = currentLocation.x - self.initialLocation.x;
|
|
|
|
newOrigin.y = currentLocation.y - self.initialLocation.y;
|
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
BOOL inMenuBar = (newOrigin.y + windowSize.height) >
|
|
|
|
(screenFrame.origin.y + screenSize.height);
|
2017-09-27 21:43:09 +00:00
|
|
|
BOOL screenAboveMainScreen = false;
|
|
|
|
|
|
|
|
if (inMenuBar) {
|
2018-04-20 18:47:04 +00:00
|
|
|
for (NSScreen* screen in [NSScreen screens]) {
|
2017-09-27 21:43:09 +00:00
|
|
|
NSRect currentScreenFrame = [screen frame];
|
2017-09-29 18:20:34 +00:00
|
|
|
BOOL isHigher = currentScreenFrame.origin.y > screenFrame.origin.y;
|
2017-09-27 21:43:09 +00:00
|
|
|
|
|
|
|
// If there's another screen that is generally above the current screen,
|
2018-04-20 18:47:04 +00:00
|
|
|
// we'll draw a new rectangle that is just above the current screen. If
|
|
|
|
// the "higher" screen intersects with this rectangle, we'll allow drawing
|
|
|
|
// above the menubar.
|
2017-09-27 21:43:09 +00:00
|
|
|
if (isHigher) {
|
2018-04-20 18:47:04 +00:00
|
|
|
NSRect aboveScreenRect =
|
|
|
|
NSMakeRect(screenFrame.origin.x,
|
|
|
|
screenFrame.origin.y + screenFrame.size.height - 10,
|
|
|
|
screenFrame.size.width, 200);
|
2017-09-29 18:20:34 +00:00
|
|
|
|
2018-04-20 18:47:04 +00:00
|
|
|
BOOL screenAboveIntersects =
|
|
|
|
NSIntersectsRect(currentScreenFrame, aboveScreenRect);
|
2017-09-27 21:43:09 +00:00
|
|
|
|
2017-09-29 18:20:34 +00:00
|
|
|
if (screenAboveIntersects) {
|
2017-09-27 21:43:09 +00:00
|
|
|
screenAboveMainScreen = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-09 18:57:57 +00:00
|
|
|
// Don't let window get dragged up under the menu bar
|
2017-09-27 21:43:09 +00:00
|
|
|
if (inMenuBar && !screenAboveMainScreen) {
|
2018-04-20 18:47:04 +00:00
|
|
|
newOrigin.y = screenFrame.origin.y +
|
|
|
|
(screenFrame.size.height - windowFrame.size.height);
|
2017-08-09 18:57:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Move the window to the new location
|
|
|
|
[self.window setFrameOrigin:newOrigin];
|
2017-08-09 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2020-11-17 04:41:37 +00:00
|
|
|
// For debugging purposes only.
|
2021-02-08 17:14:46 +00:00
|
|
|
- (void)drawDebugRect:(NSRect)aRect {
|
|
|
|
[[[NSColor greenColor] colorWithAlphaComponent:0.5] set];
|
|
|
|
NSRectFill([self bounds]);
|
2020-11-17 04:41:37 +00:00
|
|
|
}
|
2017-08-09 21:49:11 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@interface ExcludeDragRegionView : NSView
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation ExcludeDragRegionView
|
|
|
|
|
2021-02-08 17:14:46 +00:00
|
|
|
+ (void)load {
|
|
|
|
if (getenv("ELECTRON_DEBUG_DRAG_REGIONS")) {
|
|
|
|
static dispatch_once_t onceToken;
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
SEL originalSelector = @selector(drawRect:);
|
|
|
|
SEL swizzledSelector = @selector(drawDebugRect:);
|
|
|
|
|
|
|
|
Method originalMethod =
|
|
|
|
class_getInstanceMethod([self class], originalSelector);
|
|
|
|
Method swizzledMethod =
|
|
|
|
class_getInstanceMethod([self class], swizzledSelector);
|
|
|
|
BOOL didAddMethod =
|
|
|
|
class_addMethod([self class], originalSelector,
|
|
|
|
method_getImplementation(swizzledMethod),
|
|
|
|
method_getTypeEncoding(swizzledMethod));
|
|
|
|
|
|
|
|
if (didAddMethod) {
|
|
|
|
class_replaceMethod([self class], swizzledSelector,
|
|
|
|
method_getImplementation(originalMethod),
|
|
|
|
method_getTypeEncoding(originalMethod));
|
|
|
|
} else {
|
|
|
|
method_exchangeImplementations(originalMethod, swizzledMethod);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-09 21:49:11 +00:00
|
|
|
- (BOOL)mouseDownCanMoveWindow {
|
|
|
|
return NO;
|
2017-08-09 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2020-11-17 04:41:37 +00:00
|
|
|
// For debugging purposes only.
|
2021-02-08 17:14:46 +00:00
|
|
|
- (void)drawDebugRect:(NSRect)aRect {
|
|
|
|
[[[NSColor redColor] colorWithAlphaComponent:0.5] set];
|
|
|
|
NSRectFill([self bounds]);
|
2020-11-17 04:41:37 +00:00
|
|
|
}
|
2017-08-09 21:49:11 +00:00
|
|
|
|
2017-08-09 00:00:00 +00:00
|
|
|
@end
|
|
|
|
|
2019-06-19 21:23:04 +00:00
|
|
|
namespace electron {
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
|
|
|
|
NativeBrowserViewMac::NativeBrowserViewMac(
|
2018-10-19 13:50:30 +00:00
|
|
|
InspectableWebContents* inspectable_web_contents)
|
2018-03-19 07:50:30 +00:00
|
|
|
: NativeBrowserView(inspectable_web_contents) {
|
2020-09-17 00:10:49 +00:00
|
|
|
auto* iwc_view = GetInspectableWebContentsView();
|
|
|
|
if (!iwc_view)
|
|
|
|
return;
|
|
|
|
auto* view = iwc_view->GetNativeView().GetNativeNSView();
|
2017-04-12 11:40:31 +00:00
|
|
|
view.autoresizingMask = kDefaultAutoResizingMask;
|
|
|
|
}
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
|
2021-06-04 04:16:13 +00:00
|
|
|
NativeBrowserViewMac::~NativeBrowserViewMac() = default;
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
|
2017-04-12 11:40:31 +00:00
|
|
|
void NativeBrowserViewMac::SetAutoResizeFlags(uint8_t flags) {
|
|
|
|
NSAutoresizingMaskOptions autoresizing_mask = kDefaultAutoResizingMask;
|
|
|
|
if (flags & kAutoResizeWidth) {
|
|
|
|
autoresizing_mask |= NSViewWidthSizable;
|
|
|
|
}
|
|
|
|
if (flags & kAutoResizeHeight) {
|
|
|
|
autoresizing_mask |= NSViewHeightSizable;
|
|
|
|
}
|
2019-01-31 02:07:19 +00:00
|
|
|
if (flags & kAutoResizeHorizontal) {
|
|
|
|
autoresizing_mask |=
|
|
|
|
NSViewMaxXMargin | NSViewMinXMargin | NSViewWidthSizable;
|
|
|
|
}
|
|
|
|
if (flags & kAutoResizeVertical) {
|
|
|
|
autoresizing_mask |=
|
|
|
|
NSViewMaxYMargin | NSViewMinYMargin | NSViewHeightSizable;
|
|
|
|
}
|
2017-04-12 11:40:31 +00:00
|
|
|
|
2020-09-17 00:10:49 +00:00
|
|
|
auto* iwc_view = GetInspectableWebContentsView();
|
|
|
|
if (!iwc_view)
|
|
|
|
return;
|
|
|
|
auto* view = iwc_view->GetNativeView().GetNativeNSView();
|
2017-04-12 11:40:31 +00:00
|
|
|
view.autoresizingMask = autoresizing_mask;
|
|
|
|
}
|
|
|
|
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
void NativeBrowserViewMac::SetBounds(const gfx::Rect& bounds) {
|
2020-09-17 00:10:49 +00:00
|
|
|
auto* iwc_view = GetInspectableWebContentsView();
|
|
|
|
if (!iwc_view)
|
|
|
|
return;
|
|
|
|
auto* view = iwc_view->GetNativeView().GetNativeNSView();
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
auto* superview = view.superview;
|
|
|
|
const auto superview_height = superview ? superview.frame.size.height : 0;
|
2022-08-29 15:53:03 +00:00
|
|
|
|
|
|
|
// We need to use the content rect to calculate the titlebar height if the
|
|
|
|
// superview is an framed NSWindow, otherwise it will be offset incorrectly by
|
|
|
|
// the height of the titlebar.
|
|
|
|
auto titlebar_height = 0;
|
|
|
|
if (auto* win = [superview window]) {
|
|
|
|
const auto content_rect_height =
|
|
|
|
[win contentRectForFrameRect:superview.frame].size.height;
|
|
|
|
titlebar_height = superview_height - content_rect_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto new_height =
|
|
|
|
superview_height - bounds.y() - bounds.height() + titlebar_height;
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
view.frame =
|
2022-08-29 15:53:03 +00:00
|
|
|
NSMakeRect(bounds.x(), new_height, bounds.width(), bounds.height());
|
2020-10-29 19:51:56 +00:00
|
|
|
|
|
|
|
// Ensure draggable regions are properly updated to reflect new bounds.
|
|
|
|
UpdateDraggableRegions(draggable_regions_);
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
}
|
|
|
|
|
2019-07-30 02:43:05 +00:00
|
|
|
gfx::Rect NativeBrowserViewMac::GetBounds() {
|
2020-09-17 00:10:49 +00:00
|
|
|
auto* iwc_view = GetInspectableWebContentsView();
|
|
|
|
if (!iwc_view)
|
|
|
|
return gfx::Rect();
|
|
|
|
NSView* view = iwc_view->GetNativeView().GetNativeNSView();
|
2022-08-29 15:53:03 +00:00
|
|
|
auto* superview = view.superview;
|
|
|
|
const int superview_height = superview ? superview.frame.size.height : 0;
|
|
|
|
|
|
|
|
// We need to use the content rect to calculate the titlebar height if the
|
|
|
|
// superview is an framed NSWindow, otherwise it will be offset incorrectly by
|
|
|
|
// the height of the titlebar.
|
|
|
|
auto titlebar_height = 0;
|
|
|
|
if (auto* win = [superview window]) {
|
|
|
|
const auto content_rect_height =
|
|
|
|
[win contentRectForFrameRect:superview.frame].size.height;
|
|
|
|
titlebar_height = superview_height - content_rect_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto new_height = superview_height - view.frame.origin.y -
|
|
|
|
view.frame.size.height + titlebar_height;
|
|
|
|
return gfx::Rect(view.frame.origin.x, new_height, view.frame.size.width,
|
|
|
|
view.frame.size.height);
|
2019-07-30 02:43:05 +00:00
|
|
|
}
|
|
|
|
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
void NativeBrowserViewMac::SetBackgroundColor(SkColor color) {
|
2020-09-17 00:10:49 +00:00
|
|
|
auto* iwc_view = GetInspectableWebContentsView();
|
|
|
|
if (!iwc_view)
|
|
|
|
return;
|
|
|
|
auto* view = iwc_view->GetNativeView().GetNativeNSView();
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
view.wantsLayer = YES;
|
|
|
|
view.layer.backgroundColor = skia::CGColorCreateFromSkColor(color);
|
|
|
|
}
|
|
|
|
|
2017-08-09 00:00:00 +00:00
|
|
|
void NativeBrowserViewMac::UpdateDraggableRegions(
|
2020-12-01 05:02:04 +00:00
|
|
|
const std::vector<gfx::Rect>& drag_exclude_rects) {
|
2020-09-21 17:39:58 +00:00
|
|
|
if (!inspectable_web_contents_)
|
2020-09-17 00:10:49 +00:00
|
|
|
return;
|
2020-09-21 17:39:58 +00:00
|
|
|
auto* web_contents = inspectable_web_contents_->GetWebContents();
|
|
|
|
auto* iwc_view = GetInspectableWebContentsView();
|
|
|
|
NSView* web_view = web_contents->GetNativeView().GetNativeNSView();
|
2020-09-17 00:10:49 +00:00
|
|
|
NSView* inspectable_view = iwc_view->GetNativeView().GetNativeNSView();
|
2018-03-19 11:39:58 +00:00
|
|
|
NSView* window_content_view = inspectable_view.superview;
|
|
|
|
|
|
|
|
// Remove all DragRegionViews that were added last time. Note that we need
|
|
|
|
// to copy the `subviews` array to avoid mutation during iteration.
|
2018-03-19 18:45:40 +00:00
|
|
|
base::scoped_nsobject<NSArray> subviews([[web_view subviews] copy]);
|
2018-03-19 11:39:58 +00:00
|
|
|
for (NSView* subview in subviews.get()) {
|
|
|
|
if ([subview isKindOfClass:[DragRegionView class]]) {
|
2017-08-09 00:00:00 +00:00
|
|
|
[subview removeFromSuperview];
|
2018-03-19 11:39:58 +00:00
|
|
|
}
|
|
|
|
}
|
2017-08-09 00:00:00 +00:00
|
|
|
|
2017-08-09 21:49:11 +00:00
|
|
|
// Create one giant NSView that is draggable.
|
2018-03-19 11:39:58 +00:00
|
|
|
base::scoped_nsobject<NSView> drag_region_view(
|
2018-03-19 18:45:40 +00:00
|
|
|
[[DragRegionView alloc] initWithFrame:web_view.bounds]);
|
|
|
|
[web_view addSubview:drag_region_view];
|
2017-08-09 21:49:11 +00:00
|
|
|
|
2021-03-03 18:37:03 +00:00
|
|
|
// Then, on top of that, add "exclusion zones".
|
|
|
|
auto const offset = GetBounds().OffsetFromOrigin();
|
|
|
|
const auto window_content_view_height = NSHeight(window_content_view.bounds);
|
2018-03-19 11:21:03 +00:00
|
|
|
for (const auto& rect : drag_exclude_rects) {
|
2021-03-03 18:37:03 +00:00
|
|
|
const auto x = rect.x() + offset.x();
|
2021-03-19 13:22:05 +00:00
|
|
|
const auto y = window_content_view_height - (rect.bottom() + offset.y());
|
2021-03-03 18:37:03 +00:00
|
|
|
const auto exclude_rect = NSMakeRect(x, y, rect.width(), rect.height());
|
2021-03-19 13:22:05 +00:00
|
|
|
|
2018-03-19 11:39:58 +00:00
|
|
|
const auto drag_region_view_exclude_rect =
|
2021-03-03 18:37:03 +00:00
|
|
|
[window_content_view convertRect:exclude_rect toView:drag_region_view];
|
2018-03-19 11:39:58 +00:00
|
|
|
|
|
|
|
base::scoped_nsobject<NSView> exclude_drag_region_view(
|
|
|
|
[[ExcludeDragRegionView alloc]
|
|
|
|
initWithFrame:drag_region_view_exclude_rect]);
|
|
|
|
[drag_region_view addSubview:exclude_drag_region_view];
|
2017-08-09 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-01 05:02:04 +00:00
|
|
|
void NativeBrowserViewMac::UpdateDraggableRegions(
|
|
|
|
const std::vector<mojom::DraggableRegionPtr>& regions) {
|
|
|
|
if (!inspectable_web_contents_)
|
|
|
|
return;
|
|
|
|
auto* web_contents = inspectable_web_contents_->GetWebContents();
|
|
|
|
NSView* web_view = web_contents->GetNativeView().GetNativeNSView();
|
|
|
|
|
|
|
|
NSInteger webViewWidth = NSWidth([web_view bounds]);
|
|
|
|
NSInteger webViewHeight = NSHeight([web_view bounds]);
|
|
|
|
|
|
|
|
// Draggable regions are implemented by having the whole web view draggable
|
|
|
|
// and overlaying regions that are not draggable.
|
|
|
|
if (&draggable_regions_ != ®ions)
|
|
|
|
draggable_regions_ = mojo::Clone(regions);
|
|
|
|
|
|
|
|
std::vector<gfx::Rect> drag_exclude_rects;
|
2021-01-04 22:01:32 +00:00
|
|
|
if (draggable_regions_.empty()) {
|
2021-05-05 16:37:59 +00:00
|
|
|
drag_exclude_rects.emplace_back(0, 0, webViewWidth, webViewHeight);
|
2020-12-01 05:02:04 +00:00
|
|
|
} else {
|
|
|
|
drag_exclude_rects = CalculateNonDraggableRegions(
|
2021-01-04 22:01:32 +00:00
|
|
|
DraggableRegionsToSkRegion(draggable_regions_), webViewWidth,
|
|
|
|
webViewHeight);
|
2020-12-01 05:02:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
UpdateDraggableRegions(drag_exclude_rects);
|
|
|
|
}
|
|
|
|
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
// static
|
|
|
|
NativeBrowserView* NativeBrowserView::Create(
|
2018-10-19 13:50:30 +00:00
|
|
|
InspectableWebContents* inspectable_web_contents) {
|
2018-03-19 07:50:30 +00:00
|
|
|
return new NativeBrowserViewMac(inspectable_web_contents);
|
Implement initial, experimental BrowserView API
Right now, `<webview>` is the only way to embed additional content in a
`BrowserWindow`. Unfortunately `<webview>` suffers from a [number of
problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20).
To make matters worse, many of these are upstream Chromium bugs instead
of Electron-specific bugs.
For us at [Figma](https://www.figma.com), the main issue is very slow
performance.
Despite the upstream improvements to `<webview>` through the OOPIF work, it is
probable that there will continue to be `<webview>`-specific bugs in the
future.
Therefore, this introduces a `<webview>` alternative to called `BrowserView`,
which...
- is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will
likely also be bugs in `BrowserWindow` web contents)
- is instantiated in the main process like `BrowserWindow` (and unlike
`<webview>`, which lives in the DOM of a `BrowserWindow` web contents)
- needs to be added to a `BrowserWindow` to display something on the screen
This implements the most basic API. The API is expected to evolve and change in
the near future and has consequently been marked as experimental. Please do not
use this API in production unless you are prepared to deal with breaking
changes.
In the future, we will want to change the API to support multiple
`BrowserView`s per window. We will also want to consider z-ordering
auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
|
|
|
}
|
|
|
|
|
2019-06-19 21:23:04 +00:00
|
|
|
} // namespace electron
|