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

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

Issue 15650005: Create app shims with 32-bit icons only, as per OSX 10.5 spec. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: skautolockpixels Created 7 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « chrome/DEPS ('k') | chrome/chrome_browser.gypi » ('j') | 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>
7 #import <Cocoa/Cocoa.h> 8 #import <Cocoa/Cocoa.h>
8 9
9 #include "base/file_util.h" 10 #include "base/file_util.h"
10 #include "base/files/scoped_temp_dir.h" 11 #include "base/files/scoped_temp_dir.h"
11 #include "base/mac/bundle_locations.h" 12 #include "base/mac/bundle_locations.h"
12 #include "base/mac/foundation_util.h" 13 #include "base/mac/foundation_util.h"
13 #include "base/mac/mac_logging.h" 14 #include "base/mac/mac_logging.h"
14 #include "base/mac/mac_util.h" 15 #include "base/mac/mac_util.h"
15 #include "base/mac/scoped_cftyperef.h" 16 #include "base/mac/scoped_cftyperef.h"
16 #include "base/memory/scoped_nsobject.h" 17 #include "base/memory/scoped_nsobject.h"
17 #include "base/strings/sys_string_conversions.h" 18 #include "base/strings/sys_string_conversions.h"
18 #include "base/utf_string_conversions.h" 19 #include "base/utf_string_conversions.h"
19 #include "chrome/browser/web_applications/web_app.h" 20 #include "chrome/browser/web_applications/web_app.h"
20 #include "chrome/common/chrome_paths_internal.h" 21 #include "chrome/common/chrome_paths_internal.h"
21 #include "chrome/common/mac/app_mode_common.h" 22 #include "chrome/common/mac/app_mode_common.h"
22 #include "content/public/browser/browser_thread.h" 23 #include "content/public/browser/browser_thread.h"
23 #include "grit/chromium_strings.h" 24 #include "grit/chromium_strings.h"
24 #include "skia/ext/skia_utils_mac.h" 25 #include "skia/ext/skia_utils_mac.h"
25 #include "third_party/icon_family/IconFamily.h" 26 #include "third_party/skia/include/core/SkBitmap.h"
27 #include "third_party/skia/include/core/SkColor.h"
26 #include "ui/base/l10n/l10n_util_mac.h" 28 #include "ui/base/l10n/l10n_util_mac.h"
27 #include "ui/gfx/image/image_family.h" 29 #include "ui/gfx/image/image_family.h"
28 30
29 namespace { 31 namespace {
30 32
31 // Get the 100% image representation for |image|. 33 void ConvertSkiaToARGB(const SkBitmap& bitmap, char* argb) {
tapted 2013/05/22 08:27:33 This is similar to a function in skia_utils.h, but
32 // This returns the representation with the same width and height as |image| 34 SkAutoLockPixels lock(bitmap);
33 // itself. If there is no such representation, returns nil. 35 for (int y = 0; y < bitmap.height(); ++y) {
34 NSBitmapImageRep* NSImageGet100PRepresentation(NSImage* image) { 36 for (int x = 0; x < bitmap.width(); ++x) {
35 NSSize image_size = [image size]; 37 SkColor pixel = bitmap.getColor(x, y); // Unpremultiplies.
36 for (NSBitmapImageRep* image_rep in [image representations]) { 38 argb[0] = SkColorGetA(pixel);
37 NSSize image_rep_size = [image_rep size]; 39 argb[1] = SkColorGetR(pixel);
38 if (image_rep_size.width == image_size.width && 40 argb[2] = SkColorGetG(pixel);
39 image_rep_size.height == image_size.height) { 41 argb[3] = SkColorGetB(pixel);
40 return image_rep; 42 argb += 4;
41 } 43 }
42 } 44 }
43 return nil;
44 } 45 }
45 46
46 // Adds |image_rep| to |icon_family|. Returns true on success, false on failure. 47 // Adds |image| to |icon_family|. Returns true on success, false on failure.
47 bool AddBitmapImageRepToIconFamily(IconFamily* icon_family, 48 bool AddGfxImageToIconFamily(IconFamilyHandle icon_family,
48 NSBitmapImageRep* image_rep) { 49 const gfx::Image& image) {
49 NSSize size = [image_rep size]; 50 // When called via ShowCreateChromeAppShortcutsDialog the ImageFamily will
50 if (size.width != size.height) 51 // have all the representations desired here for mac, from the kDesiredSizes
52 // array in web_app_ui.cc.
53 SkBitmap bitmap = image.AsBitmap();
54 if (bitmap.config() != SkBitmap::kARGB_8888_Config ||
55 bitmap.width() != bitmap.height()) {
51 return false; 56 return false;
57 }
52 58
53 switch (static_cast<int>(size.width)) { 59 OSType icon_type;
60 switch (bitmap.width()) {
54 case 512: 61 case 512:
55 return [icon_family setIconFamilyElement:kIconServices512PixelDataARGB 62 icon_type = kIconServices512PixelDataARGB;
56 fromBitmapImageRep:image_rep]; 63 break;
57 case 256: 64 case 256:
58 return [icon_family setIconFamilyElement:kIconServices256PixelDataARGB 65 icon_type = kIconServices256PixelDataARGB;
59 fromBitmapImageRep:image_rep]; 66 break;
60 case 128: 67 case 128:
61 return [icon_family setIconFamilyElement:kThumbnail32BitData 68 icon_type = kIconServices128PixelDataARGB;
62 fromBitmapImageRep:image_rep] && 69 break;
63 [icon_family setIconFamilyElement:kThumbnail8BitMask 70 case 48:
64 fromBitmapImageRep:image_rep]; 71 icon_type = kIconServices48PixelDataARGB;
72 break;
65 case 32: 73 case 32:
66 return [icon_family setIconFamilyElement:kLarge32BitData 74 icon_type = kIconServices32PixelDataARGB;
67 fromBitmapImageRep:image_rep] && 75 break;
68 [icon_family setIconFamilyElement:kLarge8BitData
69 fromBitmapImageRep:image_rep] &&
70 [icon_family setIconFamilyElement:kLarge8BitMask
71 fromBitmapImageRep:image_rep] &&
72 [icon_family setIconFamilyElement:kLarge1BitMask
73 fromBitmapImageRep:image_rep];
74 case 16: 76 case 16:
75 return [icon_family setIconFamilyElement:kSmall32BitData 77 icon_type = kIconServices16PixelDataARGB;
76 fromBitmapImageRep:image_rep] && 78 break;
77 [icon_family setIconFamilyElement:kSmall8BitData
78 fromBitmapImageRep:image_rep] &&
79 [icon_family setIconFamilyElement:kSmall8BitMask
80 fromBitmapImageRep:image_rep] &&
81 [icon_family setIconFamilyElement:kSmall1BitMask
82 fromBitmapImageRep:image_rep];
83 default: 79 default:
84 return false; 80 return false;
85 } 81 }
82
83 Handle raw_data = NewHandle(bitmap.getSize());
benwells 2013/05/23 00:42:04 I can see that it is guaranteed by the config chec
benwells 2013/05/23 00:42:04 Is there a scoped version of the handle you can us
tapted 2013/05/23 04:03:43 Done.
tapted 2013/05/23 04:03:43 Done.
84 ConvertSkiaToARGB(bitmap, *raw_data);
85 OSErr result = SetIconFamilyData(icon_family, icon_type, raw_data);
86 DisposeHandle(raw_data);
87
88 return result == noErr;
86 } 89 }
87 90
88 base::FilePath GetWritableApplicationsDirectory() { 91 base::FilePath GetWritableApplicationsDirectory() {
89 base::FilePath path; 92 base::FilePath path;
90 if (base::mac::GetLocalDirectory(NSApplicationDirectory, &path) && 93 if (base::mac::GetLocalDirectory(NSApplicationDirectory, &path) &&
91 file_util::PathIsWritable(path)) { 94 file_util::PathIsWritable(path)) {
92 return path; 95 return path;
93 } 96 }
94 if (base::mac::GetUserDirectory(NSApplicationDirectory, &path)) 97 if (base::mac::GetUserDirectory(NSApplicationDirectory, &path))
95 return path; 98 return path;
96 return base::FilePath(); 99 return base::FilePath();
97 } 100 }
98 101
102 template <class T>
103 class ScopedCarbonHandle {
104 public:
105 ScopedCarbonHandle() {
106 typed_handle_ = reinterpret_cast<T>(NewHandle(0));
107 }
108
109 ~ScopedCarbonHandle() {
110 DisposeHandle(AsHandle());
111 }
112
113 T get() {
114 return typed_handle_;
115 }
116
117 bool WriteDataToFile(const base::FilePath& path) {
118 NSData* data = [NSData dataWithBytes:*AsHandle()
119 length:GetHandleSize(AsHandle())];
120 return [data writeToFile:base::mac::FilePathToNSString(path)
121 atomically:NO];
122 }
123
124 private:
125 Handle AsHandle() {
126 return reinterpret_cast<Handle>(typed_handle_);
127 }
128
129 T typed_handle_;
130 };
131
99 } // namespace 132 } // namespace
100 133
101
102 namespace web_app { 134 namespace web_app {
103 135
104 const char kChromeAppDirName[] = "Chrome Apps.localized"; 136 const char kChromeAppDirName[] = "Chrome Apps.localized";
105 137
106 WebAppShortcutCreator::WebAppShortcutCreator( 138 WebAppShortcutCreator::WebAppShortcutCreator(
107 const base::FilePath& user_data_dir, 139 const base::FilePath& user_data_dir,
108 const ShellIntegration::ShortcutInfo& shortcut_info, 140 const ShellIntegration::ShortcutInfo& shortcut_info,
109 const string16& chrome_bundle_id) 141 const string16& chrome_bundle_id)
110 : user_data_dir_(user_data_dir), 142 : user_data_dir_(user_data_dir),
111 info_(shortcut_info), 143 info_(shortcut_info),
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 forKey:app_mode::kCrAppModeUserDataDirKey]; 262 forKey:app_mode::kCrAppModeUserDataDirKey];
231 [plist setObject:base::mac::FilePathToNSString(info_.profile_path.BaseName()) 263 [plist setObject:base::mac::FilePathToNSString(info_.profile_path.BaseName())
232 forKey:app_mode::kCrAppModeProfileDirKey]; 264 forKey:app_mode::kCrAppModeProfileDirKey];
233 return [plist writeToFile:plist_path atomically:YES]; 265 return [plist writeToFile:plist_path atomically:YES];
234 } 266 }
235 267
236 bool WebAppShortcutCreator::UpdateIcon(const base::FilePath& app_path) const { 268 bool WebAppShortcutCreator::UpdateIcon(const base::FilePath& app_path) const {
237 if (info_.favicon.empty()) 269 if (info_.favicon.empty())
238 return true; 270 return true;
239 271
240 scoped_nsobject<IconFamily> icon_family([[IconFamily alloc] init]); 272 ScopedCarbonHandle<IconFamilyHandle> icon_family;
241 bool image_added = false; 273 bool image_added = false;
242 for (gfx::ImageFamily::const_iterator it = info_.favicon.begin(); 274 for (gfx::ImageFamily::const_iterator it = info_.favicon.begin();
243 it != info_.favicon.end(); ++it) { 275 it != info_.favicon.end(); ++it) {
244 if (it->IsEmpty()) 276 if (it->IsEmpty())
245 continue; 277 continue;
246 NSBitmapImageRep* image_rep = NSImageGet100PRepresentation(it->ToNSImage());
247 if (!image_rep)
248 continue;
249 278
250 // Missing an icon size is not fatal so don't fail if adding the bitmap 279 // Missing an icon size is not fatal so don't fail if adding the bitmap
251 // doesn't work. 280 // doesn't work.
252 if (!AddBitmapImageRepToIconFamily(icon_family, image_rep)) 281 if (!AddGfxImageToIconFamily(icon_family.get(), *it))
253 continue; 282 continue;
254 283
255 image_added = true; 284 image_added = true;
256 } 285 }
257 286
258 if (!image_added) 287 if (!image_added)
259 return false; 288 return false;
260 289
261 base::FilePath resources_path = 290 base::FilePath resources_path =
262 app_path.Append("Contents").Append("Resources"); 291 app_path.Append("Contents").Append("Resources");
263 if (!file_util::CreateDirectory(resources_path)) 292 if (!file_util::CreateDirectory(resources_path))
264 return false; 293 return false;
265 base::FilePath icon_path = resources_path.Append("app.icns"); 294
266 return [icon_family writeToFile:base::mac::FilePathToNSString(icon_path)]; 295 return icon_family.WriteDataToFile(resources_path.Append("app.icns"));
267 } 296 }
268 297
269 NSString* WebAppShortcutCreator::GetBundleIdentifier(NSDictionary* plist) const 298 NSString* WebAppShortcutCreator::GetBundleIdentifier(NSDictionary* plist) const
270 { 299 {
271 NSString* bundle_id_template = 300 NSString* bundle_id_template =
272 base::mac::ObjCCast<NSString>( 301 base::mac::ObjCCast<NSString>(
273 [plist objectForKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)]); 302 [plist objectForKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)]);
274 NSString* extension_id = base::SysUTF8ToNSString(info_.extension_id); 303 NSString* extension_id = base::SysUTF8ToNSString(info_.extension_id);
275 NSString* placeholder = 304 NSString* placeholder =
276 [NSString stringWithFormat:@"@%@@", app_mode::kShortcutIdPlaceholder]; 305 [NSString stringWithFormat:@"@%@@", app_mode::kShortcutIdPlaceholder];
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 void UpdatePlatformShortcuts( 373 void UpdatePlatformShortcuts(
345 const base::FilePath& web_app_path, 374 const base::FilePath& web_app_path,
346 const ShellIntegration::ShortcutInfo& shortcut_info) { 375 const ShellIntegration::ShortcutInfo& shortcut_info) {
347 // TODO(benwells): Implement this when shortcuts / weblings are enabled on 376 // TODO(benwells): Implement this when shortcuts / weblings are enabled on
348 // mac. 377 // mac.
349 } 378 }
350 379
351 } // namespace internals 380 } // namespace internals
352 381
353 } // namespace web_app 382 } // namespace web_app
OLDNEW
« no previous file with comments | « chrome/DEPS ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698