Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(257)

Side by Side Diff: chrome/browser/web_applications/web_app_mac.mm

Issue 2404793002: Mac: Write gfx::ImageFamily using CGImageDestination. (Closed)
Patch Set: Check finalize. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "chrome/browser/web_applications/web_app_mac.h" 5 #import "chrome/browser/web_applications/web_app_mac.h"
6 6
7 #import <Carbon/Carbon.h>
8 #import <Cocoa/Cocoa.h> 7 #import <Cocoa/Cocoa.h>
9 #include <stdint.h> 8 #include <stdint.h>
10 9
11 #include <utility> 10 #include <utility>
12 11
13 #include "base/command_line.h" 12 #include "base/command_line.h"
14 #include "base/files/file_enumerator.h" 13 #include "base/files/file_enumerator.h"
15 #include "base/files/file_util.h" 14 #include "base/files/file_util.h"
16 #include "base/files/scoped_temp_dir.h" 15 #include "base/files/scoped_temp_dir.h"
17 #include "base/mac/foundation_util.h" 16 #include "base/mac/foundation_util.h"
(...skipping 29 matching lines...) Expand all
47 #include "chrome/grit/generated_resources.h" 46 #include "chrome/grit/generated_resources.h"
48 #include "components/crx_file/id_util.h" 47 #include "components/crx_file/id_util.h"
49 #include "components/version_info/version_info.h" 48 #include "components/version_info/version_info.h"
50 #include "content/public/browser/browser_thread.h" 49 #include "content/public/browser/browser_thread.h"
51 #include "content/public/common/content_switches.h" 50 #include "content/public/common/content_switches.h"
52 #include "extensions/browser/extension_registry.h" 51 #include "extensions/browser/extension_registry.h"
53 #include "extensions/common/extension.h" 52 #include "extensions/common/extension.h"
54 #import "skia/ext/skia_utils_mac.h" 53 #import "skia/ext/skia_utils_mac.h"
55 #include "third_party/skia/include/core/SkBitmap.h" 54 #include "third_party/skia/include/core/SkBitmap.h"
56 #include "third_party/skia/include/core/SkColor.h" 55 #include "third_party/skia/include/core/SkColor.h"
56 #include "third_party/skia/include/utils/mac/SkCGUtils.h"
57 #include "ui/base/l10n/l10n_util.h" 57 #include "ui/base/l10n/l10n_util.h"
58 #include "ui/base/resource/resource_bundle.h" 58 #include "ui/base/resource/resource_bundle.h"
59 #include "ui/gfx/image/image_family.h" 59 #include "ui/gfx/image/image_family.h"
60 60
61 bool g_app_shims_allow_update_and_launch_in_tests = false; 61 bool g_app_shims_allow_update_and_launch_in_tests = false;
62 62
63 namespace { 63 namespace {
64 64
65 // Launch Services Key to run as an agent app, which doesn't launch in the dock. 65 // Launch Services Key to run as an agent app, which doesn't launch in the dock.
66 NSString* const kLSUIElement = @"LSUIElement"; 66 NSString* const kLSUIElement = @"LSUIElement";
(...skipping 19 matching lines...) Expand all
86 content::BrowserThread::UI>; 86 content::BrowserThread::UI>;
87 87
88 ~Latch() { callback_.Run(); } 88 ~Latch() { callback_.Run(); }
89 void NoOp() {} 89 void NoOp() {}
90 90
91 base::Closure callback_; 91 base::Closure callback_;
92 92
93 DISALLOW_COPY_AND_ASSIGN(Latch); 93 DISALLOW_COPY_AND_ASSIGN(Latch);
94 }; 94 };
95 95
96 class ScopedCarbonHandle { 96 class MacIconWriter {
97 public: 97 public:
98 ScopedCarbonHandle(size_t initial_size) : handle_(NewHandle(initial_size)) { 98 explicit MacIconWriter(size_t image_count)
Matt Giuca 2016/10/11 02:36:50 This is mostly gibberish to me. Maybe add a Mac pe
tapted 2016/10/12 02:04:13 Done.
99 DCHECK(handle_); 99 : data_([[NSMutableData alloc] initWithCapacity:0]) {
100 DCHECK_EQ(noErr, MemError()); 100 image_destination_.reset(CGImageDestinationCreateWithData(
101 base::mac::NSToCFCast(data_), kUTTypeAppleICNS, image_count, nullptr));
102 DCHECK(image_destination_);
101 } 103 }
102 ~ScopedCarbonHandle() { DisposeHandle(handle_); } 104 ~MacIconWriter() {}
103 105
104 Handle Get() { return handle_; } 106 bool WriteDataToFile(const base::FilePath& path) {
105 char* Data() { return *handle_; } 107 if (CGImageDestinationFinalize(image_destination_)) {
106 size_t HandleSize() const { return GetHandleSize(handle_); } 108 return
107 109 [data_ writeToFile:base::mac::FilePathToNSString(path) atomically:NO];
108 IconFamilyHandle GetAsIconFamilyHandle() { 110 }
109 return reinterpret_cast<IconFamilyHandle>(handle_); 111 NOTREACHED() << "CGImageDestinationFinalize failed.";
112 return false;
110 } 113 }
111 114
112 bool WriteDataToFile(const base::FilePath& path) { 115 void AddIcon(const gfx::Image& image) {
113 NSData* data = [NSData dataWithBytes:Data() 116 base::ScopedCFTypeRef<CGImageRef> cg_image(SkCreateCGImageRefWithColorspace(
114 length:HandleSize()]; 117 *image.ToSkBitmap(), base::mac::GetSRGBColorSpace()));
115 return [data writeToFile:base::mac::FilePathToNSString(path) 118 CGImageDestinationAddImage(image_destination_, cg_image, nullptr);
116 atomically:NO];
117 } 119 }
118 120
119 private: 121 private:
120 Handle handle_; 122 base::scoped_nsobject<NSMutableData> data_;
123 base::ScopedCFTypeRef<CGImageDestinationRef> image_destination_;
124
125 DISALLOW_COPY_AND_ASSIGN(MacIconWriter);
121 }; 126 };
122 127
123 void ConvertSkiaToARGB(const SkBitmap& bitmap, ScopedCarbonHandle* handle) { 128 // Adds |image| to |icon_family|. Returns true on success, false on failure.
Matt Giuca 2016/10/11 02:36:50 Wrong comment.
tapted 2016/10/12 02:04:13 Done.
124 CHECK_EQ(4u * bitmap.width() * bitmap.height(), handle->HandleSize()); 129 bool IsImageValidForIcon(const gfx::Image& image) {
130 if (image.IsEmpty())
131 return false;
125 132
126 char* argb = handle->Data();
127 SkAutoLockPixels lock(bitmap);
128 for (int y = 0; y < bitmap.height(); ++y) {
129 for (int x = 0; x < bitmap.width(); ++x) {
130 SkColor pixel = bitmap.getColor(x, y);
131 argb[0] = SkColorGetA(pixel);
132 argb[1] = SkColorGetR(pixel);
133 argb[2] = SkColorGetG(pixel);
134 argb[3] = SkColorGetB(pixel);
135 argb += 4;
136 }
137 }
138 }
139
140 // Adds |image| to |icon_family|. Returns true on success, false on failure.
141 bool AddGfxImageToIconFamily(IconFamilyHandle icon_family,
142 const gfx::Image& image) {
143 // When called via ShowCreateChromeAppShortcutsDialog the ImageFamily will 133 // When called via ShowCreateChromeAppShortcutsDialog the ImageFamily will
144 // have all the representations desired here for mac, from the kDesiredSizes 134 // have all the representations desired here for mac, from the kDesiredSizes
145 // array in web_app.cc. 135 // array in web_app.cc.
146 SkBitmap bitmap = image.AsBitmap(); 136 SkBitmap bitmap = image.AsBitmap();
147 if (bitmap.colorType() != kN32_SkColorType || 137 if (bitmap.colorType() != kN32_SkColorType ||
148 bitmap.width() != bitmap.height()) { 138 bitmap.width() != bitmap.height()) {
149 return false; 139 return false;
150 } 140 }
151 141
152 OSType icon_type;
153 switch (bitmap.width()) { 142 switch (bitmap.width()) {
154 case 512: 143 case 512:
155 icon_type = kIconServices512PixelDataARGB;
156 break;
157 case 256: 144 case 256:
158 icon_type = kIconServices256PixelDataARGB;
159 break;
160 case 128: 145 case 128:
161 icon_type = kIconServices128PixelDataARGB;
162 break;
163 case 48: 146 case 48:
164 icon_type = kIconServices48PixelDataARGB;
165 break;
166 case 32: 147 case 32:
167 icon_type = kIconServices32PixelDataARGB;
168 break;
169 case 16: 148 case 16:
170 icon_type = kIconServices16PixelDataARGB; 149 return true;
171 break;
172 default:
173 return false;
174 } 150 }
175 151 return false;
176 ScopedCarbonHandle raw_data(bitmap.getSize());
177 ConvertSkiaToARGB(bitmap, &raw_data);
178 OSErr result = SetIconFamilyData(icon_family, icon_type, raw_data.Get());
179 DCHECK_EQ(noErr, result);
180 return result == noErr;
181 } 152 }
182 153
183 bool AppShimsDisabledForTest() { 154 bool AppShimsDisabledForTest() {
184 // Disable app shims in tests because shims created in ~/Applications will not 155 // Disable app shims in tests because shims created in ~/Applications will not
185 // be cleaned up. 156 // be cleaned up.
186 return base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType); 157 return base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType);
187 } 158 }
188 159
189 base::FilePath GetWritableApplicationsDirectory() { 160 base::FilePath GetWritableApplicationsDirectory() {
190 base::FilePath path; 161 base::FilePath path;
(...skipping 778 matching lines...) Expand 10 before | Expand all | Expand 10 after
969 NSString* localized_path = base::mac::FilePathToNSString( 940 NSString* localized_path = base::mac::FilePathToNSString(
970 localized_dir.Append("InfoPlist.strings")); 941 localized_dir.Append("InfoPlist.strings"));
971 return [strings_plist writeToFile:localized_path 942 return [strings_plist writeToFile:localized_path
972 atomically:YES]; 943 atomically:YES];
973 } 944 }
974 945
975 bool WebAppShortcutCreator::UpdateIcon(const base::FilePath& app_path) const { 946 bool WebAppShortcutCreator::UpdateIcon(const base::FilePath& app_path) const {
976 if (info_->favicon.empty()) 947 if (info_->favicon.empty())
977 return true; 948 return true;
978 949
979 ScopedCarbonHandle icon_family(0); 950 size_t image_count = 0;
980 bool image_added = false;
981 for (gfx::ImageFamily::const_iterator it = info_->favicon.begin(); 951 for (gfx::ImageFamily::const_iterator it = info_->favicon.begin();
982 it != info_->favicon.end(); ++it) { 952 it != info_->favicon.end(); ++it) {
983 if (it->IsEmpty()) 953 if (IsImageValidForIcon(*it))
Matt Giuca 2016/10/11 02:36:50 I think instead of calling this function twice, it
tapted 2016/10/12 02:04:13 Done. (and actually it's neater just to have a fun
954 ++image_count;
955 }
956 if (image_count == 0)
957 return false;
958
959 MacIconWriter icon_family(image_count);
Matt Giuca 2016/10/11 02:36:50 Can we rename this to |icon_writer|. (The name ic
tapted 2016/10/12 02:04:13 Done (obsoleted).
960 for (gfx::ImageFamily::const_iterator it = info_->favicon.begin();
961 it != info_->favicon.end(); ++it) {
962 if (!IsImageValidForIcon(*it))
984 continue; 963 continue;
985 964
986 // Missing an icon size is not fatal so don't fail if adding the bitmap 965 icon_family.AddIcon(*it);
987 // doesn't work.
988 if (!AddGfxImageToIconFamily(icon_family.GetAsIconFamilyHandle(), *it))
989 continue;
990
991 image_added = true;
992 } 966 }
993 967
994 if (!image_added)
995 return false;
996
997 base::FilePath resources_path = GetResourcesPath(app_path); 968 base::FilePath resources_path = GetResourcesPath(app_path);
998 if (!base::CreateDirectory(resources_path)) 969 if (!base::CreateDirectory(resources_path))
999 return false; 970 return false;
1000 971
1001 return icon_family.WriteDataToFile(resources_path.Append("app.icns")); 972 return icon_family.WriteDataToFile(resources_path.Append("app.icns"));
1002 } 973 }
1003 974
1004 bool WebAppShortcutCreator::UpdateInternalBundleIdentifier() const { 975 bool WebAppShortcutCreator::UpdateInternalBundleIdentifier() const {
1005 NSString* plist_path = GetPlistPath(GetInternalShortcutPath()); 976 NSString* plist_path = GetPlistPath(GetInternalShortcutPath());
1006 NSMutableDictionary* plist = ReadPlist(plist_path); 977 NSMutableDictionary* plist = ReadPlist(plist_path);
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
1177 BuildShortcutInfoFromBundle(*it); 1148 BuildShortcutInfoFromBundle(*it);
1178 WebAppShortcutCreator shortcut_creator(it->DirName(), shortcut_info.get(), 1149 WebAppShortcutCreator shortcut_creator(it->DirName(), shortcut_info.get(),
1179 extensions::FileHandlersInfo()); 1150 extensions::FileHandlersInfo());
1180 shortcut_creator.DeleteShortcuts(); 1151 shortcut_creator.DeleteShortcuts();
1181 } 1152 }
1182 } 1153 }
1183 1154
1184 } // namespace internals 1155 } // namespace internals
1185 1156
1186 } // namespace web_app 1157 } // namespace web_app
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698