feat: support more color formats for backgroundColor (#31868)

This commit is contained in:
Shelley Vohr 2022-03-21 18:35:54 +01:00 committed by GitHub
parent 4b8b492b62
commit db79734bfb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 144 additions and 55 deletions

View file

@ -70,5 +70,31 @@ The `bounds` of this BrowserView instance as `Object`.
#### `view.setBackgroundColor(color)` _Experimental_ #### `view.setBackgroundColor(color)` _Experimental_
* `color` string - Color in `#aarrggbb` or `#argb` form. The alpha channel is * `color` string - Color in Hex, RGB, ARGB, HSL, HSLA or named CSS color format. The alpha channel is
optional. optional for the hex type.
Examples of valid `color` values:
* Hex
* #fff (RGB)
* #ffff (ARGB)
* #ffffff (RRGGBB)
* #ffffffff (AARRGGBB)
* RGB
* rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)
* e.g. rgb(255, 255, 255)
* RGBA
* rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)
* e.g. rgba(255, 255, 255, 1.0)
* HSL
* hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)
* e.g. hsl(200, 20%, 50%)
* HSLA
* hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)
* e.g. hsla(200, 20%, 50%, 0.5)
* Color name
* Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148)
* Similar to CSS Color Module Level 3 keywords, but case-sensitive.
* e.g. `blueviolet` or `red`
**Note:** Hex format with alpha takes `AARRGGBB` or `ARGB`, _not_ `RRGGBBA` or `RGA`.

View file

@ -66,6 +66,18 @@ win.loadURL('https://github.com')
Note that even for apps that use `ready-to-show` event, it is still recommended Note that even for apps that use `ready-to-show` event, it is still recommended
to set `backgroundColor` to make the app feel more native. to set `backgroundColor` to make the app feel more native.
Some examples of valid `backgroundColor` values include:
```js
const win = new BrowserWindow()
win.setBackgroundColor('hsl(230, 100%, 50%)')
win.setBackgroundColor('rgb(255, 145, 145)')
win.setBackgroundColor('#ff00a3')
win.setBackgroundColor('blueviolet')
```
For more information about these color types see valid options in [win.setBackgroundColor](browser-window.md#winsetbackgroundcolorbackgroundcolor).
## Parent and child windows ## Parent and child windows
By using `parent` option, you can create child windows: By using `parent` option, you can create child windows:
@ -199,9 +211,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
* `enableLargerThanScreen` boolean (optional) - Enable the window to be resized larger * `enableLargerThanScreen` boolean (optional) - Enable the window to be resized larger
than screen. Only relevant for macOS, as other OSes allow than screen. Only relevant for macOS, as other OSes allow
larger-than-screen windows by default. Default is `false`. larger-than-screen windows by default. Default is `false`.
* `backgroundColor` string (optional) - Window's background color as a hexadecimal value, * `backgroundColor` string (optional) - The window's background color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. Alpha in #AARRGGBB format is supported if `transparent` is set to `true`. Default is `#FFF` (white). See [win.setBackgroundColor](browser-window.md#winsetbackgroundcolorbackgroundcolor) for more information.
like `#66CD00` or `#FFF` or `#80FFFFFF` (alpha in #AARRGGBB format is supported if
`transparent` is set to `true`). Default is `#FFF` (white).
* `hasShadow` boolean (optional) - Whether window should have a shadow. Default is `true`. * `hasShadow` boolean (optional) - Whether window should have a shadow. Default is `true`.
* `opacity` number (optional) - Set the initial opacity of the window, between 0.0 (fully * `opacity` number (optional) - Set the initial opacity of the window, between 0.0 (fully
transparent) and 1.0 (fully opaque). This is only implemented on Windows and macOS. transparent) and 1.0 (fully opaque). This is only implemented on Windows and macOS.
@ -992,12 +1002,33 @@ APIs like `win.setSize`.
#### `win.setBackgroundColor(backgroundColor)` #### `win.setBackgroundColor(backgroundColor)`
* `backgroundColor` string - Window's background color as a hexadecimal value, * `backgroundColor` string - Color in Hex, RGB, RGBA, HSL, HSLA or named CSS color format. The alpha channel is optional for the hex type.
like `#66CD00` or `#FFF` or `#80FFFFFF` (alpha is supported if `transparent`
is `true`). Default is `#FFF` (white).
Sets the background color of the window. See [Setting Examples of valid `backgroundColor` values:
`backgroundColor`](#setting-the-backgroundcolor-property).
* Hex
* #fff (shorthand RGB)
* #ffff (shorthand ARGB)
* #ffffff (RGB)
* #ffffffff (ARGB)
* RGB
* rgb\(([\d]+),\s*([\d]+),\s*([\d]+)\)
* e.g. rgb(255, 255, 255)
* RGBA
* rgba\(([\d]+),\s*([\d]+),\s*([\d]+),\s*([\d.]+)\)
* e.g. rgba(255, 255, 255, 1.0)
* HSL
* hsl\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%\)
* e.g. hsl(200, 20%, 50%)
* HSLA
* hsla\((-?[\d.]+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)
* e.g. hsla(200, 20%, 50%, 0.5)
* Color name
* Options are listed in [SkParseColor.cpp](https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/src/utils/SkParseColor.cpp;l=11-152;drc=eea4bf52cb0d55e2a39c828b017c80a5ee054148)
* Similar to CSS Color Module Level 3 keywords, but case-sensitive.
* e.g. `blueviolet` or `red`
Sets the background color of the window. See [Setting `backgroundColor`](#setting-the-backgroundcolor-property).
#### `win.previewFile(path[, displayName])` _macOS_ #### `win.previewFile(path[, displayName])` _macOS_
@ -1041,8 +1072,11 @@ Returns [`Rectangle`](structures/rectangle.md) - The `bounds` of the window as `
#### `win.getBackgroundColor()` #### `win.getBackgroundColor()`
Returns `string` - Gets the background color of the window. See [Setting Returns `string` - Gets the background color of the window in Hex (`#RRGGBB`) format.
`backgroundColor`](#setting-the-backgroundcolor-property).
See [Setting `backgroundColor`](#setting-the-backgroundcolor-property).
**Note:** The alpha value is _not_ returned alongside the red, green, and blue values.
#### `win.setContentBounds(bounds[, animate])` #### `win.setContentBounds(bounds[, animate])`

View file

@ -643,11 +643,11 @@ bool BaseWindow::IsTabletMode() const {
} }
void BaseWindow::SetBackgroundColor(const std::string& color_name) { void BaseWindow::SetBackgroundColor(const std::string& color_name) {
SkColor color = ParseHexColor(color_name); SkColor color = ParseCSSColor(color_name);
window_->SetBackgroundColor(color); window_->SetBackgroundColor(color);
} }
std::string BaseWindow::GetBackgroundColor() { std::string BaseWindow::GetBackgroundColor(gin_helper::Arguments* args) {
return ToRGBHex(window_->GetBackgroundColor()); return ToRGBHex(window_->GetBackgroundColor());
} }

View file

@ -159,7 +159,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
bool IsKiosk(); bool IsKiosk();
bool IsTabletMode() const; bool IsTabletMode() const;
virtual void SetBackgroundColor(const std::string& color_name); virtual void SetBackgroundColor(const std::string& color_name);
std::string GetBackgroundColor(); std::string GetBackgroundColor(gin_helper::Arguments* args);
void SetHasShadow(bool has_shadow); void SetHasShadow(bool has_shadow);
bool HasShadow(); bool HasShadow();
void SetOpacity(const double opacity); void SetOpacity(const double opacity);

View file

@ -154,11 +154,11 @@ gfx::Rect BrowserView::GetBounds() {
} }
void BrowserView::SetBackgroundColor(const std::string& color_name) { void BrowserView::SetBackgroundColor(const std::string& color_name) {
view_->SetBackgroundColor(ParseHexColor(color_name)); view_->SetBackgroundColor(ParseCSSColor(color_name));
if (web_contents()) { if (web_contents()) {
auto* wc = web_contents()->web_contents(); auto* wc = web_contents()->web_contents();
wc->SetPageBaseBackgroundColor(ParseHexColor(color_name)); wc->SetPageBaseBackgroundColor(ParseCSSColor(color_name));
} }
} }

View file

@ -370,7 +370,7 @@ void BrowserWindow::Blur() {
void BrowserWindow::SetBackgroundColor(const std::string& color_name) { void BrowserWindow::SetBackgroundColor(const std::string& color_name) {
BaseWindow::SetBackgroundColor(color_name); BaseWindow::SetBackgroundColor(color_name);
SkColor color = ParseHexColor(color_name); SkColor color = ParseCSSColor(color_name);
web_contents()->SetPageBaseBackgroundColor(color); web_contents()->SetPageBaseBackgroundColor(color);
auto* rwhv = web_contents()->GetRenderWidgetHostView(); auto* rwhv = web_contents()->GetRenderWidgetHostView();
if (rwhv) { if (rwhv) {
@ -384,7 +384,7 @@ void BrowserWindow::SetBackgroundColor(const std::string& color_name) {
auto* web_preferences = auto* web_preferences =
WebContentsPreferences::From(api_web_contents_->web_contents()); WebContentsPreferences::From(api_web_contents_->web_contents());
if (web_preferences) { if (web_preferences) {
web_preferences->SetBackgroundColor(ParseHexColor(color_name)); web_preferences->SetBackgroundColor(ParseCSSColor(color_name));
} }
} }
} }

View file

@ -773,7 +773,7 @@ WebContents::WebContents(v8::Isolate* isolate,
// and we then need to pull it back out and check it here. // and we then need to pull it back out and check it here.
std::string background_color; std::string background_color;
options.GetHidden(options::kBackgroundColor, &background_color); options.GetHidden(options::kBackgroundColor, &background_color);
bool transparent = ParseHexColor(background_color) == SK_ColorTRANSPARENT; bool transparent = ParseCSSColor(background_color) == SK_ColorTRANSPARENT;
content::WebContents::CreateParams params(session->browser_context()); content::WebContents::CreateParams params(session->browser_context());
auto* view = new OffScreenWebContentsView( auto* view = new OffScreenWebContentsView(

View file

@ -241,7 +241,7 @@ void NativeWindow::InitFromOptions(const gin_helper::Dictionary& options) {
#endif #endif
std::string color; std::string color;
if (options.Get(options::kBackgroundColor, &color)) { if (options.Get(options::kBackgroundColor, &color)) {
SetBackgroundColor(ParseHexColor(color)); SetBackgroundColor(ParseCSSColor(color));
} else if (!transparent()) { } else if (!transparent()) {
// For normal window, use white as default background. // For normal window, use white as default background.
SetBackgroundColor(SK_ColorWHITE); SetBackgroundColor(SK_ColorWHITE);

View file

@ -339,7 +339,7 @@ static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item";
} }
- (NSColor*)colorFromHexColorString:(const std::string&)colorString { - (NSColor*)colorFromHexColorString:(const std::string&)colorString {
SkColor color = electron::ParseHexColor(colorString); SkColor color = electron::ParseCSSColor(colorString);
return skia::SkColorToDeviceNSColor(color); return skia::SkColorToDeviceNSColor(color);
} }

View file

@ -235,7 +235,7 @@ void WebContentsPreferences::Merge(
} }
std::string background_color; std::string background_color;
if (web_preferences.GetHidden(options::kBackgroundColor, &background_color)) if (web_preferences.GetHidden(options::kBackgroundColor, &background_color))
background_color_ = ParseHexColor(background_color); background_color_ = ParseCSSColor(background_color);
std::string safe_dialogs_message; std::string safe_dialogs_message;
if (web_preferences.Get("safeDialogsMessage", &safe_dialogs_message)) if (web_preferences.Get("safeDialogsMessage", &safe_dialogs_message))
safe_dialogs_message_ = safe_dialogs_message; safe_dialogs_message_ = safe_dialogs_message;

View file

@ -4,46 +4,54 @@
#include "shell/common/color_util.h" #include "shell/common/color_util.h"
#include <cmath>
#include <utility>
#include <vector> #include <vector>
#include "base/strings/string_number_conversions.h" #include "base/cxx17_backports.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "content/public/common/color_parser.h"
#include "ui/gfx/color_utils.h"
namespace {
bool IsHexFormat(const std::string& str) {
// Must be either #ARGB or #AARRGGBB.
bool is_hex_length = str.length() == 5 || str.length() == 9;
if (str[0] != '#' || !is_hex_length)
return false;
if (!std::all_of(str.begin() + 1, str.end(), ::isxdigit))
return false;
return true;
}
} // namespace
namespace electron { namespace electron {
SkColor ParseHexColor(const std::string& color_string) { SkColor ParseCSSColor(const std::string& color_string) {
// Check the string for incorrect formatting. // ParseCssColorString expects RGBA and we historically use ARGB
if (color_string.empty() || color_string[0] != '#') // so we need to convert before passing to ParseCssColorString.
return SK_ColorWHITE; std::string color_str = color_string;
if (IsHexFormat(color_str)) {
// Prepend FF if alpha channel is not specified. if (color_str.length() == 5) {
std::string source = color_string.substr(1); // #ARGB => #RGBA
if (source.size() == 3) std::swap(color_str[1], color_str[4]);
source.insert(0, "F"); } else {
else if (source.size() == 6) // #AARRGGBB => #RRGGBBAA
source.insert(0, "FF"); std::swap(color_str[1], color_str[7]);
std::swap(color_str[2], color_str[8]);
// Convert the string from #FFF format to #FFFFFF format.
std::string formatted_color;
if (source.size() == 4) {
for (size_t i = 0; i < 4; ++i) {
formatted_color += source[i];
formatted_color += source[i];
} }
} else if (source.size() == 8) {
formatted_color = source;
} else {
return SK_ColorWHITE;
} }
// Convert the string to an integer and make sure it is in the correct value SkColor color;
// range. if (!content::ParseCssColorString(color_str, &color))
std::vector<uint8_t> bytes; color = SK_ColorWHITE;
if (!base::HexStringToBytes(formatted_color, &bytes))
return SK_ColorWHITE;
return SkColorSetARGB(bytes[0], bytes[1], bytes[2], bytes[3]); return color;
} }
std::string ToRGBHex(SkColor color) { std::string ToRGBHex(SkColor color) {

View file

@ -11,12 +11,14 @@
namespace electron { namespace electron {
// Parse hex color like "#FFF" or "#EFEFEF" // Parses a CSS-style color string from hex, rgb(), rgba(),
SkColor ParseHexColor(const std::string& color_string); // hsl(), hsla(), or color name formats.
SkColor ParseCSSColor(const std::string& color_string);
// Convert color to RGB hex value like "#ABCDEF" // Convert color to RGB hex value like "#RRGGBB".
std::string ToRGBHex(SkColor color); std::string ToRGBHex(SkColor color);
// Convert color to RGBA hex value like "#RRGGBBAA".
std::string ToRGBAHex(SkColor color, bool include_hash = true); std::string ToRGBAHex(SkColor color, bool include_hash = true);
} // namespace electron } // namespace electron

View file

@ -1076,6 +1076,25 @@ describe('BrowserWindow module', () => {
w.setBackgroundColor(backgroundColor); w.setBackgroundColor(backgroundColor);
expect(w.getBackgroundColor()).to.equal(backgroundColor); expect(w.getBackgroundColor()).to.equal(backgroundColor);
}); });
it('returns correct color with multiple passed formats', () => {
w.destroy();
w = new BrowserWindow({});
w.setBackgroundColor('#AABBFF');
expect(w.getBackgroundColor()).to.equal('#AABBFF');
w.setBackgroundColor('blueviolet');
expect(w.getBackgroundColor()).to.equal('#8A2BE2');
w.setBackgroundColor('rgb(255, 0, 185)');
expect(w.getBackgroundColor()).to.equal('#FF00B9');
w.setBackgroundColor('rgba(245, 40, 145, 0.8)');
expect(w.getBackgroundColor()).to.equal('#F52891');
w.setBackgroundColor('hsl(155, 100%, 50%)');
expect(w.getBackgroundColor()).to.equal('#00FF95');
});
}); });
describe('BrowserWindow.getNormalBounds()', () => { describe('BrowserWindow.getNormalBounds()', () => {