Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add transparent webpreference to webview #40301

Merged
merged 16 commits into from Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/api/webview-tag.md
Expand Up @@ -221,7 +221,9 @@ windows. Popups are disabled by default.
```

A `string` which is a comma separated list of strings which specifies the web preferences to be set on the webview.
The full list of supported preference strings can be found in [BrowserWindow](browser-window.md#new-browserwindowoptions).
The full list of supported preference strings can be found in [BrowserWindow](browser-window.md#new-browserwindowoptions). In addition, webview supports the following preferences:

* `transparent` boolean (optional) - Whether to enable background transparency for the guest page. Default is `true`. **Note:** The guest page's text and background colors are derived from the [color scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) of its root element. When transparency is enabled, the text color will still change accordingly but the background will remain transparent.

The string follows the same format as the features string in `window.open`.
A name by itself is given a `true` boolean value.
Expand Down
5 changes: 4 additions & 1 deletion shell/browser/api/electron_api_web_contents.cc
Expand Up @@ -822,6 +822,9 @@ WebContents::WebContents(v8::Isolate* isolate,
// Get type
options.Get("type", &type_);

// Get transparent for guest view
options.Get("transparent", &guest_transparent_);

bool b = false;
if (options.Get(options::kOffscreen, &b) && b)
type_ = Type::kOffScreen;
Expand Down Expand Up @@ -3778,7 +3781,7 @@ void WebContents::SetImageAnimationPolicy(const std::string& new_policy) {
}

void WebContents::SetBackgroundColor(absl::optional<SkColor> maybe_color) {
SkColor color = maybe_color.value_or(type_ == Type::kWebView ||
SkColor color = maybe_color.value_or((IsGuest() && guest_transparent_) ||
type_ == Type::kBrowserView
? SK_ColorTRANSPARENT
: SK_ColorWHITE);
Expand Down
3 changes: 3 additions & 0 deletions shell/browser/api/electron_api_web_contents.h
Expand Up @@ -801,6 +801,9 @@ class WebContents : public ExclusiveAccessContext,
// The type of current WebContents.
Type type_ = Type::kBrowserWindow;

// Weather the guest view should be transparent
bool guest_transparent_ = true;

int32_t id_;

// Request id used for findInPage request.
Expand Down
15 changes: 15 additions & 0 deletions spec/fixtures/pages/flex-webview.html
@@ -0,0 +1,15 @@
<style>
html,
body {
height: 100%;
}

body {
display: flex;
margin: 0;
}

webview {
flex: 1;
}
</style>
82 changes: 81 additions & 1 deletion spec/webview-spec.ts
@@ -1,6 +1,6 @@
import * as path from 'node:path';
import * as url from 'node:url';
import { BrowserWindow, session, ipcMain, app, WebContents } from 'electron/main';
import { BrowserWindow, session, ipcMain, app, WebContents, screen } from 'electron/main';
import { closeAllWindows } from './lib/window-helpers';
import { emittedUntil } from './lib/events-helpers';
import { ifit, ifdescribe, defer, itremote, useRemoteContext, listen } from './lib/spec-helpers';
Expand All @@ -9,6 +9,7 @@ import * as http from 'node:http';
import * as auth from 'basic-auth';
import { once } from 'node:events';
import { setTimeout } from 'node:timers/promises';
import { areColorsSimilar, captureScreen, HexColors, getPixelColor } from './lib/screen-helpers';

declare let WebView: any;
const features = process._linkedBinding('electron_common_features');
Expand Down Expand Up @@ -773,6 +774,85 @@ describe('<webview> tag', function () {
});
});

describe('webpreferences attribute', () => {
const WINDOW_BACKGROUND_COLOR = '#55ccbb';

let w: BrowserWindow;
before(async () => {
w = new BrowserWindow({
webPreferences: {
webviewTag: true,
nodeIntegration: true,
contextIsolation: false
}
});
await w.loadURL(`file://${fixtures}/pages/flex-webview.html`);
w.setBackgroundColor(WINDOW_BACKGROUND_COLOR);
});
afterEach(async () => {
await w.webContents.executeJavaScript(`{
for (const el of document.querySelectorAll('webview')) el.remove();
}`);
});
after(() => w.close());

// Linux and arm64 platforms (WOA and macOS) do not return any capture sources
ifit(process.platform === 'darwin' && process.arch === 'x64')('is transparent by default', async () => {
await loadWebView(w.webContents, {
src: 'data:text/html,foo'
});

await setTimeout(1000);

const display = screen.getPrimaryDisplay();
const screenCapture = await captureScreen();
const centerColor = getPixelColor(screenCapture, {
x: display.size.width / 2,
y: display.size.height / 2
});

expect(areColorsSimilar(centerColor, WINDOW_BACKGROUND_COLOR)).to.be.true();
});

// Linux and arm64 platforms (WOA and macOS) do not return any capture sources
ifit(process.platform === 'darwin' && process.arch === 'x64')('remains transparent when set', async () => {
await loadWebView(w.webContents, {
src: 'data:text/html,foo',
webpreferences: 'transparent=yes'
});

await setTimeout(1000);

const display = screen.getPrimaryDisplay();
const screenCapture = await captureScreen();
const centerColor = getPixelColor(screenCapture, {
x: display.size.width / 2,
y: display.size.height / 2
});

expect(areColorsSimilar(centerColor, WINDOW_BACKGROUND_COLOR)).to.be.true();
});

// Linux and arm64 platforms (WOA and macOS) do not return any capture sources
ifit(process.platform === 'darwin' && process.arch === 'x64')('can disable transparency', async () => {
await loadWebView(w.webContents, {
src: 'data:text/html,foo',
webpreferences: 'transparent=no'
});

await setTimeout(1000);

const display = screen.getPrimaryDisplay();
const screenCapture = await captureScreen();
const centerColor = getPixelColor(screenCapture, {
x: display.size.width / 2,
y: display.size.height / 2
});

expect(areColorsSimilar(centerColor, HexColors.WHITE)).to.be.true();
});
});

describe('permission request handlers', () => {
let w: BrowserWindow;
beforeEach(async () => {
Expand Down