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 3 // found in the LICENSE file. 4 5 #include "ui/base/resource/resource_bundle.h" 6 7 #import <AppKit/AppKit.h> 8 9 #include "base/basictypes.h" 10 #include "base/file_util.h" 11 #include "base/files/file_path.h" 12 #include "base/mac/bundle_locations.h" 13 #include "base/mac/mac_util.h" 14 #include "base/mac/scoped_nsobject.h" 15 #include "base/memory/ref_counted_memory.h" 16 #include "base/strings/sys_string_conversions.h" 17 #include "base/synchronization/lock.h" 18 #include "ui/base/resource/resource_handle.h" 19 #include "ui/gfx/image/image.h" 20 21 namespace ui { 22 23 namespace { 24 25 base::FilePath GetResourcesPakFilePath(NSString* name, NSString* mac_locale) { 26 NSString *resource_path; 27 // Some of the helper processes need to be able to fetch resources 28 // (chrome_main.cc: SubprocessNeedsResourceBundle()). Fetch the same locale 29 // as the already-running browser instead of using what NSBundle might pick 30 // based on values at helper launch time. 31 if ([mac_locale length]) { 32 resource_path = [base::mac::FrameworkBundle() pathForResource:name 33 ofType:@"pak" 34 inDirectory:@"" 35 forLocalization:mac_locale]; 36 } else { 37 resource_path = [base::mac::FrameworkBundle() pathForResource:name 38 ofType:@"pak"]; 39 } 40 41 if (!resource_path) { 42 // Return just the name of the pack file. 43 return base::FilePath(base::SysNSStringToUTF8(name) + ".pak"); 44 } 45 46 return base::FilePath([resource_path fileSystemRepresentation]); 47 } 48 49 } // namespace 50 51 void ResourceBundle::LoadCommonResources() { 52 AddDataPackFromPath(GetResourcesPakFilePath(@"chrome", nil), 53 SCALE_FACTOR_NONE); 54 AddDataPackFromPath(GetResourcesPakFilePath(@"chrome_100_percent", 55 nil), SCALE_FACTOR_100P); 56 AddDataPackFromPath(GetResourcesPakFilePath(@"webkit_resources_100_percent", 57 nil), SCALE_FACTOR_100P); 58 59 // On Mac we load 1x and 2x resources and we let the UI framework decide 60 // which one to use. 61 if (IsScaleFactorSupported(SCALE_FACTOR_200P)) { 62 AddDataPackFromPath(GetResourcesPakFilePath(@"chrome_200_percent", 63 nil), SCALE_FACTOR_200P); 64 AddDataPackFromPath(GetResourcesPakFilePath(@"webkit_resources_200_percent", 65 nil), SCALE_FACTOR_200P); 66 } 67 } 68 69 base::FilePath ResourceBundle::GetLocaleFilePath(const std::string& app_locale, 70 bool test_file_exists) { 71 NSString* mac_locale = base::SysUTF8ToNSString(app_locale); 72 73 // Mac OS X uses "_" instead of "-", so swap to get a Mac-style value. 74 mac_locale = [mac_locale stringByReplacingOccurrencesOfString:@"-" 75 withString:@"_"]; 76 77 // On disk, the "en_US" resources are just "en" (http://crbug.com/25578). 78 if ([mac_locale isEqual:@"en_US"]) 79 mac_locale = @"en"; 80 81 base::FilePath locale_file_path = 82 GetResourcesPakFilePath(@"locale", mac_locale); 83 84 if (delegate_) { 85 locale_file_path = 86 delegate_->GetPathForLocalePack(locale_file_path, app_locale); 87 } 88 89 // Don't try to load empty values or values that are not absolute paths. 90 if (locale_file_path.empty() || !locale_file_path.IsAbsolute()) 91 return base::FilePath(); 92 93 if (test_file_exists && !base::PathExists(locale_file_path)) 94 return base::FilePath(); 95 96 return locale_file_path; 97 } 98 99 gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id, ImageRTL rtl) { 100 // Flipped images are not used on Mac. 101 DCHECK_EQ(rtl, RTL_DISABLED); 102 103 // Check to see if the image is already in the cache. 104 { 105 base::AutoLock lock(*images_and_fonts_lock_); 106 if (images_.count(resource_id)) { 107 if (!images_[resource_id].HasRepresentation(gfx::Image::kImageRepCocoa)) { 108 DLOG(WARNING) << "ResourceBundle::GetNativeImageNamed() is returning a" 109 << " cached gfx::Image that isn't backed by an NSImage. The image" 110 << " will be converted, rather than going through the NSImage loader." 111 << " resource_id = " << resource_id; 112 } 113 return images_[resource_id]; 114 } 115 } 116 117 gfx::Image image; 118 if (delegate_) 119 image = delegate_->GetNativeImageNamed(resource_id, rtl); 120 121 if (image.IsEmpty()) { 122 base::scoped_nsobject<NSImage> ns_image; 123 for (size_t i = 0; i < data_packs_.size(); ++i) { 124 scoped_refptr<base::RefCountedStaticMemory> data( 125 data_packs_[i]->GetStaticMemory(resource_id)); 126 if (!data.get()) 127 continue; 128 129 base::scoped_nsobject<NSData> ns_data( 130 [[NSData alloc] initWithBytes:data->front() length:data->size()]); 131 if (!ns_image.get()) { 132 ns_image.reset([[NSImage alloc] initWithData:ns_data]); 133 } else { 134 NSImageRep* image_rep = [NSBitmapImageRep imageRepWithData:ns_data]; 135 if (image_rep) 136 [ns_image addRepresentation:image_rep]; 137 } 138 } 139 140 if (!ns_image.get()) { 141 LOG(WARNING) << "Unable to load image with id " << resource_id; 142 NOTREACHED(); // Want to assert in debug mode. 143 return GetEmptyImage(); 144 } 145 146 image = gfx::Image(ns_image.release()); 147 } 148 149 base::AutoLock lock(*images_and_fonts_lock_); 150 151 // Another thread raced the load and has already cached the image. 152 if (images_.count(resource_id)) 153 return images_[resource_id]; 154 155 images_[resource_id] = image; 156 return images_[resource_id]; 157 } 158 159 } // namespace ui 160