diff --git a/atom.gyp b/atom.gyp index a34a5af042f7..3a08bd070572 100644 --- a/atom.gyp +++ b/atom.gyp @@ -238,6 +238,7 @@ 'atom/common/native_mate_converters/gurl_converter.h', 'atom/common/native_mate_converters/image_converter.cc', 'atom/common/native_mate_converters/image_converter.h', + 'atom/common/native_mate_converters/image_converter_mac.mm', 'atom/common/native_mate_converters/string16_converter.h', 'atom/common/native_mate_converters/v8_value_converter.cc', 'atom/common/native_mate_converters/v8_value_converter.h', diff --git a/atom/browser/api/atom_api_tray.cc b/atom/browser/api/atom_api_tray.cc index dfb0d6e1d102..6315c4059d43 100644 --- a/atom/browser/api/atom_api_tray.cc +++ b/atom/browser/api/atom_api_tray.cc @@ -12,6 +12,7 @@ #include "atom/common/native_mate_converters/string16_converter.h" #include "native_mate/constructor.h" #include "native_mate/dictionary.h" +#include "ui/gfx/image/image.h" #include "atom/common/node_includes.h" @@ -19,7 +20,7 @@ namespace atom { namespace api { -Tray::Tray(const gfx::ImageSkia& image) +Tray::Tray(const gfx::Image& image) : tray_icon_(TrayIcon::Create()) { tray_icon_->SetImage(image); tray_icon_->AddObserver(this); @@ -29,7 +30,7 @@ Tray::~Tray() { } // static -mate::Wrappable* Tray::New(const gfx::ImageSkia& image) { +mate::Wrappable* Tray::New(const gfx::Image& image) { return new Tray(image); } @@ -57,13 +58,13 @@ void Tray::Destroy() { tray_icon_.reset(); } -void Tray::SetImage(mate::Arguments* args, const gfx::ImageSkia& image) { +void Tray::SetImage(mate::Arguments* args, const gfx::Image& image) { if (!CheckTrayLife(args)) return; tray_icon_->SetImage(image); } -void Tray::SetPressedImage(mate::Arguments* args, const gfx::ImageSkia& image) { +void Tray::SetPressedImage(mate::Arguments* args, const gfx::Image& image) { if (!CheckTrayLife(args)) return; tray_icon_->SetPressedImage(image); @@ -92,7 +93,7 @@ void Tray::DisplayBalloon(mate::Arguments* args, if (!CheckTrayLife(args)) return; - gfx::ImageSkia icon; + gfx::Image icon; options.Get("icon", &icon); base::string16 title, content; if (!options.Get("title", &title) || diff --git a/atom/browser/api/atom_api_tray.h b/atom/browser/api/atom_api_tray.h index 87bc84a50148..48828d2c9366 100644 --- a/atom/browser/api/atom_api_tray.h +++ b/atom/browser/api/atom_api_tray.h @@ -12,7 +12,7 @@ #include "base/memory/scoped_ptr.h" namespace gfx { -class ImageSkia; +class Image; } namespace mate { @@ -31,13 +31,13 @@ class Menu; class Tray : public mate::EventEmitter, public TrayIconObserver { public: - static mate::Wrappable* New(const gfx::ImageSkia& image); + static mate::Wrappable* New(const gfx::Image& image); static void BuildPrototype(v8::Isolate* isolate, v8::Handle prototype); protected: - explicit Tray(const gfx::ImageSkia& image); + explicit Tray(const gfx::Image& image); virtual ~Tray(); // TrayIconObserver: @@ -48,8 +48,8 @@ class Tray : public mate::EventEmitter, void OnBalloonClosed() override; void Destroy(); - void SetImage(mate::Arguments* args, const gfx::ImageSkia& image); - void SetPressedImage(mate::Arguments* args, const gfx::ImageSkia& image); + void SetImage(mate::Arguments* args, const gfx::Image& image); + void SetPressedImage(mate::Arguments* args, const gfx::Image& image); void SetToolTip(mate::Arguments* args, const std::string& tool_tip); void SetTitle(mate::Arguments* args, const std::string& title); void SetHighlightMode(mate::Arguments* args, bool highlight); diff --git a/atom/browser/ui/tray_icon.cc b/atom/browser/ui/tray_icon.cc index c8fb40902d46..68770c1e5cfd 100644 --- a/atom/browser/ui/tray_icon.cc +++ b/atom/browser/ui/tray_icon.cc @@ -12,7 +12,7 @@ TrayIcon::TrayIcon() { TrayIcon::~TrayIcon() { } -void TrayIcon::SetPressedImage(const gfx::ImageSkia& image) { +void TrayIcon::SetPressedImage(const gfx::Image& image) { } void TrayIcon::SetTitle(const std::string& title) { @@ -21,7 +21,7 @@ void TrayIcon::SetTitle(const std::string& title) { void TrayIcon::SetHighlightMode(bool highlight) { } -void TrayIcon::DisplayBalloon(const gfx::ImageSkia& icon, +void TrayIcon::DisplayBalloon(const gfx::Image& icon, const base::string16& title, const base::string16& contents) { } diff --git a/atom/browser/ui/tray_icon.h b/atom/browser/ui/tray_icon.h index a27ea82f224e..6293b39002b6 100644 --- a/atom/browser/ui/tray_icon.h +++ b/atom/browser/ui/tray_icon.h @@ -20,10 +20,10 @@ class TrayIcon { virtual ~TrayIcon(); // Sets the image associated with this status icon. - virtual void SetImage(const gfx::ImageSkia& image) = 0; + virtual void SetImage(const gfx::Image& image) = 0; // Sets the image associated with this status icon when pressed. - virtual void SetPressedImage(const gfx::ImageSkia& image); + virtual void SetPressedImage(const gfx::Image& image); // Sets the hover text for this status icon. This is also used as the label // for the menu item which is created as a replacement for the status icon @@ -41,7 +41,7 @@ class TrayIcon { // Displays a notification balloon with the specified contents. // Depending on the platform it might not appear by the icon tray. - virtual void DisplayBalloon(const gfx::ImageSkia& icon, + virtual void DisplayBalloon(const gfx::Image& icon, const base::string16& title, const base::string16& contents); diff --git a/atom/browser/ui/tray_icon_cocoa.h b/atom/browser/ui/tray_icon_cocoa.h index bec04147af59..8d0cd5d5e290 100644 --- a/atom/browser/ui/tray_icon_cocoa.h +++ b/atom/browser/ui/tray_icon_cocoa.h @@ -22,8 +22,8 @@ class TrayIconCocoa : public TrayIcon { TrayIconCocoa(); virtual ~TrayIconCocoa(); - virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE; - virtual void SetPressedImage(const gfx::ImageSkia& image) OVERRIDE; + virtual void SetImage(const gfx::Image& image) OVERRIDE; + virtual void SetPressedImage(const gfx::Image& image) OVERRIDE; virtual void SetToolTip(const std::string& tool_tip) OVERRIDE; virtual void SetTitle(const std::string& title) OVERRIDE; virtual void SetHighlightMode(bool highlight) OVERRIDE; diff --git a/atom/browser/ui/tray_icon_cocoa.mm b/atom/browser/ui/tray_icon_cocoa.mm index 143e767831a8..408ba29a14e0 100644 --- a/atom/browser/ui/tray_icon_cocoa.mm +++ b/atom/browser/ui/tray_icon_cocoa.mm @@ -53,20 +53,14 @@ TrayIconCocoa::~TrayIconCocoa() { [[NSStatusBar systemStatusBar] removeStatusItem:item_]; } -void TrayIconCocoa::SetImage(const gfx::ImageSkia& image) { - if (!image.isNull()) { - gfx::Image neutral(image); - if (!neutral.IsEmpty()) - [item_ setImage:neutral.ToNSImage()]; - } +void TrayIconCocoa::SetImage(const gfx::Image& image) { + if (!image.IsEmpty()) + [item_ setImage:image.ToNSImage()]; } -void TrayIconCocoa::SetPressedImage(const gfx::ImageSkia& image) { - if (!image.isNull()) { - gfx::Image neutral(image); - if (!neutral.IsEmpty()) - [item_ setAlternateImage:neutral.ToNSImage()]; - } +void TrayIconCocoa::SetPressedImage(const gfx::Image& image) { + if (!image.IsEmpty()) + [item_ setAlternateImage:image.ToNSImage()]; } void TrayIconCocoa::SetToolTip(const std::string& tool_tip) { diff --git a/atom/browser/ui/tray_icon_gtk.cc b/atom/browser/ui/tray_icon_gtk.cc index c7a56ddb037e..d95109c26e66 100644 --- a/atom/browser/ui/tray_icon_gtk.cc +++ b/atom/browser/ui/tray_icon_gtk.cc @@ -8,6 +8,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/ui/libgtk2ui/app_indicator_icon.h" #include "chrome/browser/ui/libgtk2ui/gtk2_status_icon.h" +#include "ui/gfx/image/image.h" namespace atom { @@ -17,18 +18,18 @@ TrayIconGtk::TrayIconGtk() { TrayIconGtk::~TrayIconGtk() { } -void TrayIconGtk::SetImage(const gfx::ImageSkia& image) { +void TrayIconGtk::SetImage(const gfx::Image& image) { if (icon_) { - icon_->SetImage(image); + icon_->SetImage(image.AsImageSkia()); return; } base::string16 empty; if (libgtk2ui::AppIndicatorIcon::CouldOpen()) - icon_.reset( - new libgtk2ui::AppIndicatorIcon(base::GenerateGUID(), image, empty)); + icon_.reset(new libgtk2ui::AppIndicatorIcon( + base::GenerateGUID(), image.AsImageSkia(), empty)); else - icon_.reset(new libgtk2ui::Gtk2StatusIcon(image, empty)); + icon_.reset(new libgtk2ui::Gtk2StatusIcon(image.AsImageSkia(), empty)); icon_->set_delegate(this); } diff --git a/atom/browser/ui/tray_icon_gtk.h b/atom/browser/ui/tray_icon_gtk.h index 5027a2d44891..ce9ae3cf2b7e 100644 --- a/atom/browser/ui/tray_icon_gtk.h +++ b/atom/browser/ui/tray_icon_gtk.h @@ -23,7 +23,7 @@ class TrayIconGtk : public TrayIcon, virtual ~TrayIconGtk(); // TrayIcon: - virtual void SetImage(const gfx::ImageSkia& image) OVERRIDE; + virtual void SetImage(const gfx::Image& image) OVERRIDE; virtual void SetToolTip(const std::string& tool_tip) OVERRIDE; virtual void SetContextMenu(ui::SimpleMenuModel* menu_model) OVERRIDE; diff --git a/atom/browser/ui/win/notify_icon.cc b/atom/browser/ui/win/notify_icon.cc index 97842989559e..1a472e2edc1a 100644 --- a/atom/browser/ui/win/notify_icon.cc +++ b/atom/browser/ui/win/notify_icon.cc @@ -10,6 +10,7 @@ #include "base/win/windows_version.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/icon_util.h" +#include "ui/gfx/image/image.h" #include "ui/gfx/point.h" #include "ui/gfx/rect.h" #include "ui/views/controls/menu/menu_runner.h" @@ -90,19 +91,19 @@ void NotifyIcon::ResetIcon() { LOG(WARNING) << "Unable to re-create status tray icon."; } -void NotifyIcon::SetImage(const gfx::ImageSkia& image) { +void NotifyIcon::SetImage(const gfx::Image& image) { // Create the icon. NOTIFYICONDATA icon_data; InitIconData(&icon_data); icon_data.uFlags = NIF_ICON; - icon_.Set(IconUtil::CreateHICONFromSkBitmap(*image.bitmap())); + icon_.Set(IconUtil::CreateHICONFromSkBitmap(image.AsBitmap())); icon_data.hIcon = icon_.Get(); BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); if (!result) LOG(WARNING) << "Error setting status tray icon image"; } -void NotifyIcon::SetPressedImage(const gfx::ImageSkia& image) { +void NotifyIcon::SetPressedImage(const gfx::Image& image) { // Ignore pressed images, since the standard on Windows is to not highlight // pressed status icons. } @@ -118,7 +119,7 @@ void NotifyIcon::SetToolTip(const std::string& tool_tip) { LOG(WARNING) << "Unable to set tooltip for status tray icon"; } -void NotifyIcon::DisplayBalloon(const gfx::ImageSkia& icon, +void NotifyIcon::DisplayBalloon(const gfx::Image& icon, const base::string16& title, const base::string16& contents) { NOTIFYICONDATA icon_data; @@ -130,8 +131,8 @@ void NotifyIcon::DisplayBalloon(const gfx::ImageSkia& icon, icon_data.uTimeout = 0; base::win::Version win_version = base::win::GetVersion(); - if (!icon.isNull() && win_version != base::win::VERSION_PRE_XP) { - balloon_icon_.Set(IconUtil::CreateHICONFromSkBitmap(*icon.bitmap())); + if (!icon.IsEmpty() && win_version != base::win::VERSION_PRE_XP) { + balloon_icon_.Set(IconUtil::CreateHICONFromSkBitmap(icon.AsBitmap())); icon_data.hBalloonIcon = balloon_icon_.Get(); icon_data.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON; } diff --git a/atom/browser/ui/win/notify_icon.h b/atom/browser/ui/win/notify_icon.h index 2ac309d5dbaf..12eea1fcf725 100644 --- a/atom/browser/ui/win/notify_icon.h +++ b/atom/browser/ui/win/notify_icon.h @@ -43,10 +43,10 @@ class NotifyIcon : public TrayIcon { UINT message_id() const { return message_id_; } // Overridden from TrayIcon: - void SetImage(const gfx::ImageSkia& image) override; - void SetPressedImage(const gfx::ImageSkia& image) override; + void SetImage(const gfx::Image& image) override; + void SetPressedImage(const gfx::Image& image) override; void SetToolTip(const std::string& tool_tip) override; - void DisplayBalloon(const gfx::ImageSkia& icon, + void DisplayBalloon(const gfx::Image& icon, const base::string16& title, const base::string16& contents) override; void SetContextMenu(ui::SimpleMenuModel* menu_model) override; diff --git a/atom/common/native_mate_converters/image_converter.cc b/atom/common/native_mate_converters/image_converter.cc index 7f4a434d97c4..d4a33eb5ec5b 100644 --- a/atom/common/native_mate_converters/image_converter.cc +++ b/atom/common/native_mate_converters/image_converter.cc @@ -12,9 +12,12 @@ #include "base/strings/string_util.h" #include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/codec/png_codec.h" +#include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" #include "ui/base/layout.h" +#if !defined(OS_MACOSX) + namespace mate { namespace { @@ -29,6 +32,8 @@ ScaleFactorPair kScaleFactorPairs[] = { { "@2x" , 2.0f }, { "@3x" , 3.0f }, { "@1x" , 1.0f }, + { "@4x" , 4.0f }, + { "@5x" , 5.0f }, { "@1.25x" , 1.25f }, { "@1.33x" , 1.33f }, { "@1.4x" , 1.4f }, @@ -40,10 +45,6 @@ ScaleFactorPair kScaleFactorPairs[] = { float GetScaleFactorFromPath(const base::FilePath& path) { std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe()); - // There is no scale info in the file path. - if (!EndsWith(filename, "x", true)) - return 1.0f; - // We don't try to convert string to float here because it is very very // expensive. for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) { @@ -54,27 +55,9 @@ float GetScaleFactorFromPath(const base::FilePath& path) { return 1.0f; } -void AppendIfExists(std::vector* paths, - const base::FilePath& path) { - if (base::PathExists(path)) - paths->push_back(path); -} - -void PopulatePossibleFilePaths(std::vector* paths, - const base::FilePath& path) { - AppendIfExists(paths, path); - - std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe()); - if (MatchPattern(filename, "*@*x")) - return; - - for (unsigned i = 0; i < arraysize(kScaleFactorPairs); ++i) - AppendIfExists(paths, - path.InsertBeforeExtensionASCII(kScaleFactorPairs[i].name)); -} - -bool AddImageSkiaRepFromPath(gfx::ImageSkia* image, - const base::FilePath& path) { +bool AddImageSkiaRep(gfx::ImageSkia* image, + const base::FilePath& path, + double scale_factor) { std::string file_contents; if (!base::ReadFileToString(path, &file_contents)) return false; @@ -89,13 +72,28 @@ bool AddImageSkiaRepFromPath(gfx::ImageSkia* image, // Try JPEG. decoded.reset(gfx::JPEGCodec::Decode(data, size)); - if (decoded) { - image->AddRepresentation(gfx::ImageSkiaRep( - *decoded.release(), GetScaleFactorFromPath(path))); - return true; - } + if (!decoded) + return false; - return false; + image->AddRepresentation(gfx::ImageSkiaRep(*decoded.release(), scale_factor)); + return true; +} + +bool PopulateImageSkiaRepsFromPath(gfx::ImageSkia* image, + const base::FilePath& path) { + bool succeed = false; + std::string filename(path.BaseName().RemoveExtension().AsUTF8Unsafe()); + if (MatchPattern(filename, "*@*x")) + // Don't search for other representations if the DPI has been specified. + return AddImageSkiaRep(image, path, GetScaleFactorFromPath(path)); + else + succeed |= AddImageSkiaRep(image, path, 1.0f); + + for (const ScaleFactorPair& pair : kScaleFactorPairs) + succeed |= AddImageSkiaRep(image, + path.InsertBeforeExtensionASCII(pair.name), + pair.scale); + return succeed; } } // namespace @@ -104,20 +102,23 @@ bool Converter::FromV8(v8::Isolate* isolate, v8::Handle val, gfx::ImageSkia* out) { base::FilePath path; - if (Converter::FromV8(isolate, val, &path)) { - std::vector paths; - PopulatePossibleFilePaths(&paths, path); - if (paths.empty()) - return false; + if (!Converter::FromV8(isolate, val, &path)) + return false; - for (size_t i = 0; i < paths.size(); ++i) { - if (!AddImageSkiaRepFromPath(out, paths[i])) - return false; - } - return true; - } + return PopulateImageSkiaRepsFromPath(out, path); +} - return false; +bool Converter::FromV8(v8::Isolate* isolate, + v8::Handle val, + gfx::Image* out) { + gfx::ImageSkia image; + if (!ConvertFromV8(isolate, val, &image)) + return false; + + *out = gfx::Image(image); + return true; } } // namespace mate + +#endif // !defined(OS_MACOSX) diff --git a/atom/common/native_mate_converters/image_converter.h b/atom/common/native_mate_converters/image_converter.h index 53de920d6e0b..738b50ad7416 100644 --- a/atom/common/native_mate_converters/image_converter.h +++ b/atom/common/native_mate_converters/image_converter.h @@ -8,6 +8,7 @@ #include "native_mate/converter.h" namespace gfx { +class Image; class ImageSkia; } @@ -20,6 +21,13 @@ struct Converter { gfx::ImageSkia* out); }; +template<> +struct Converter { + static bool FromV8(v8::Isolate* isolate, + v8::Handle val, + gfx::Image* out); +}; + } // namespace mate #endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_IMAGE_CONVERTER_H_ diff --git a/atom/common/native_mate_converters/image_converter_mac.mm b/atom/common/native_mate_converters/image_converter_mac.mm new file mode 100644 index 000000000000..5bc2ead9f57e --- /dev/null +++ b/atom/common/native_mate_converters/image_converter_mac.mm @@ -0,0 +1,61 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/common/native_mate_converters/image_converter.h" + +#import + +#include "base/mac/foundation_util.h" +#include "base/mac/scoped_nsobject.h" +#include "base/strings/string_util.h" +#include "base/strings/sys_string_conversions.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/image/image_skia.h" + +namespace { + +bool IsTemplateImage(const std::string& path) { + return (MatchPattern(path, "*Template.*") || + MatchPattern(path, "*Template@*x.*")); +} + +} // namespace + +namespace mate { + +bool Converter::FromV8(v8::Isolate* isolate, + v8::Handle val, + gfx::ImageSkia* out) { + gfx::Image image; + if (!ConvertFromV8(isolate, val, &image) || image.IsEmpty()) + return false; + + gfx::ImageSkia image_skia = image.AsImageSkia(); + if (image_skia.isNull()) + return false; + + *out = image_skia; + return true; +} + +bool Converter::FromV8(v8::Isolate* isolate, + v8::Handle val, + gfx::Image* out) { + std::string path; + if (!ConvertFromV8(isolate, val, &path)) + return false; + + base::scoped_nsobject image([[NSImage alloc] + initByReferencingFile:base::SysUTF8ToNSString(path)]); + if (![image isValid]) + return false; + + if (IsTemplateImage(path)) + [image setTemplate:YES]; + + *out = gfx::Image(image.release()); + return true; +} + +} // namespace mate diff --git a/docs/api/image.md b/docs/api/image.md index 75545e99ade1..d7cf8aeea733 100644 --- a/docs/api/image.md +++ b/docs/api/image.md @@ -13,7 +13,10 @@ var window = new BrowserWindow({icon: '/Users/somebody/images/window.png'}); ## Supported formats -Only `PNG` and `JPG` formats are supported, and `PNG` format is preferred. +On Mac all formats supported by the system can be used, while on Linux and +Windows only `PNG` and `JPG` formats are supported. + +So it is recommended to use `PNG` images for all cases. ## High resolution image @@ -51,4 +54,22 @@ Following suffixes as DPI denses are also supported: * `@2x` * `@2.5x` * `@3x` +* `@4x` +* `@5x` +## Template image + +Template images consist of black and clear colors (and an alpha channel). +Template images are not intended to be used as standalone images and are usually +mixed with other content to create the desired final appearance. + +The most common case is to use template image for menu bar icon so it can adapt +to both light and dark menu bars. + +Template image is only supported on Mac. + +To mark an image as template image, its filename should end with the word +`Template`, examples are: + +* `xxxTemplate.png` +* `xxxTemplate@2x.png` diff --git a/vendor/native_mate b/vendor/native_mate index 4a1d11b2bea0..be2934d9b592 160000 --- a/vendor/native_mate +++ b/vendor/native_mate @@ -1 +1 @@ -Subproject commit 4a1d11b2bea0907c66bf986ab635e161a1a16385 +Subproject commit be2934d9b5925cb017238c1b385340c2f9cfdcb7