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 #ifndef UI_BASE_RESOURCE_RESOURCE_BUNDLE_H_ 6 #define UI_BASE_RESOURCE_RESOURCE_BUNDLE_H_ 7 8 #include <map> 9 #include <string> 10 11 #include "base/basictypes.h" 12 #include "base/containers/hash_tables.h" 13 #include "base/files/file_path.h" 14 #include "base/files/memory_mapped_file.h" 15 #include "base/gtest_prod_util.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/memory/scoped_vector.h" 18 #include "base/strings/string16.h" 19 #include "base/strings/string_piece.h" 20 #include "build/build_config.h" 21 #include "ui/base/layout.h" 22 #include "ui/base/ui_base_export.h" 23 #include "ui/gfx/font_list.h" 24 #include "ui/gfx/image/image.h" 25 #include "ui/gfx/native_widget_types.h" 26 27 class SkBitmap; 28 29 namespace base { 30 class File; 31 class Lock; 32 class RefCountedStaticMemory; 33 } 34 35 namespace ui { 36 37 class DataPack; 38 class ResourceHandle; 39 40 // ResourceBundle is a central facility to load images and other resources, 41 // such as theme graphics. Every resource is loaded only once. 42 class UI_BASE_EXPORT ResourceBundle { 43 public: 44 // An enumeration of the various font styles used throughout Chrome. 45 // The following holds true for the font sizes: 46 // Small <= SmallBold <= Base <= Bold <= Medium <= MediumBold <= Large. 47 enum FontStyle { 48 // NOTE: depending upon the locale, using one of the *BoldFont below 49 // may *not* actually result in a bold font. 50 SmallFont, 51 SmallBoldFont, 52 BaseFont, 53 BoldFont, 54 MediumFont, 55 MediumBoldFont, 56 LargeFont, 57 LargeBoldFont, 58 }; 59 60 enum ImageRTL { 61 // Images are flipped in RTL locales. 62 RTL_ENABLED, 63 // Images are never flipped. 64 RTL_DISABLED, 65 }; 66 67 enum LoadResources { 68 LOAD_COMMON_RESOURCES, 69 DO_NOT_LOAD_COMMON_RESOURCES 70 }; 71 72 // Delegate class that allows interception of pack file loading and resource 73 // requests. The methods of this class may be called on multiple threads. 74 class Delegate { 75 public: 76 // Called before a resource pack file is loaded. Return the full path for 77 // the pack file to continue loading or an empty value to cancel loading. 78 // |pack_path| will contain the complete default path for the pack file if 79 // known or just the pack file name otherwise. 80 virtual base::FilePath GetPathForResourcePack( 81 const base::FilePath& pack_path, 82 ScaleFactor scale_factor) = 0; 83 84 // Called before a locale pack file is loaded. Return the full path for 85 // the pack file to continue loading or an empty value to cancel loading. 86 // |pack_path| will contain the complete default path for the pack file if 87 // known or just the pack file name otherwise. 88 virtual base::FilePath GetPathForLocalePack( 89 const base::FilePath& pack_path, 90 const std::string& locale) = 0; 91 92 // Return an image resource or an empty value to attempt retrieval of the 93 // default resource. 94 virtual gfx::Image GetImageNamed(int resource_id) = 0; 95 96 // Return an image resource or an empty value to attempt retrieval of the 97 // default resource. 98 virtual gfx::Image GetNativeImageNamed(int resource_id, ImageRTL rtl) = 0; 99 100 // Return a static memory resource or NULL to attempt retrieval of the 101 // default resource. 102 virtual base::RefCountedStaticMemory* LoadDataResourceBytes( 103 int resource_id, 104 ScaleFactor scale_factor) = 0; 105 106 // Retrieve a raw data resource. Return true if a resource was provided or 107 // false to attempt retrieval of the default resource. 108 virtual bool GetRawDataResource(int resource_id, 109 ScaleFactor scale_factor, 110 base::StringPiece* value) = 0; 111 112 // Retrieve a localized string. Return true if a string was provided or 113 // false to attempt retrieval of the default string. 114 virtual bool GetLocalizedString(int message_id, base::string16* value) = 0; 115 116 // Returns a font or NULL to attempt retrieval of the default resource. 117 virtual scoped_ptr<gfx::Font> GetFont(FontStyle style) = 0; 118 119 protected: ~Delegate()120 virtual ~Delegate() {} 121 }; 122 123 // Initialize the ResourceBundle for this process. Does not take ownership of 124 // the |delegate| value. Returns the language selected. 125 // NOTE: Mac ignores this and always loads up resources for the language 126 // defined by the Cocoa UI (i.e., NSBundle does the language work). 127 // 128 // TODO(sergeyu): This method also loads common resources (i.e. chrome.pak). 129 // There is no way to specify which resource files are loaded, i.e. names of 130 // the files are hardcoded in ResourceBundle. Fix it to allow to specify which 131 // files are loaded (e.g. add a new method in Delegate). 132 // |load_resources| controls whether or not LoadCommonResources is called. 133 static std::string InitSharedInstanceWithLocale( 134 const std::string& pref_locale, 135 Delegate* delegate, 136 LoadResources load_resources); 137 138 // Initialize the ResourceBundle using the given file region. If |region| is 139 // MemoryMappedFile::Region::kWholeFile, the entire |pak_file| is used. 140 // This allows the use of this function in a sandbox without local file 141 // access (as on Android). 142 static void InitSharedInstanceWithPakFileRegion( 143 base::File pak_file, 144 const base::MemoryMappedFile::Region& region); 145 146 // Initialize the ResourceBundle using given data pack path for testing. 147 static void InitSharedInstanceWithPakPath(const base::FilePath& path); 148 149 // Delete the ResourceBundle for this process if it exists. 150 static void CleanupSharedInstance(); 151 152 // Returns true after the global resource loader instance has been created. 153 static bool HasSharedInstance(); 154 155 // Return the global resource loader instance. 156 static ResourceBundle& GetSharedInstance(); 157 158 // Check if the .pak for the given locale exists. 159 bool LocaleDataPakExists(const std::string& locale); 160 161 // Registers additional data pack files with this ResourceBundle. When 162 // looking for a DataResource, we will search these files after searching the 163 // main module. |path| should be the complete path to the pack file if known 164 // or just the pack file name otherwise (the delegate may optionally override 165 // this value). |scale_factor| is the scale of images in this resource pak 166 // relative to the images in the 1x resource pak. This method is not thread 167 // safe! You should call it immediately after calling InitSharedInstance. 168 void AddDataPackFromPath(const base::FilePath& path, 169 ScaleFactor scale_factor); 170 171 // Same as above but using an already open file. 172 void AddDataPackFromFile(base::File file, ScaleFactor scale_factor); 173 174 // Same as above but using only a region (offset + size) of the file. 175 void AddDataPackFromFileRegion(base::File file, 176 const base::MemoryMappedFile::Region& region, 177 ScaleFactor scale_factor); 178 179 // Same as AddDataPackFromPath but does not log an error if the pack fails to 180 // load. 181 void AddOptionalDataPackFromPath(const base::FilePath& path, 182 ScaleFactor scale_factor); 183 184 // Changes the locale for an already-initialized ResourceBundle, returning the 185 // name of the newly-loaded locale. Future calls to get strings will return 186 // the strings for this new locale. This has no effect on existing or future 187 // image resources. |locale_resources_data_| is protected by a lock for the 188 // duration of the swap, as GetLocalizedString() may be concurrently invoked 189 // on another thread. 190 std::string ReloadLocaleResources(const std::string& pref_locale); 191 192 // Gets image with the specified resource_id from the current module data. 193 // Returns a pointer to a shared instance of gfx::ImageSkia. This shared 194 // instance is owned by the resource bundle and should not be freed. 195 // TODO(pkotwicz): Make method return const gfx::ImageSkia* 196 // 197 // NOTE: GetNativeImageNamed is preferred for cross-platform gfx::Image use. 198 gfx::ImageSkia* GetImageSkiaNamed(int resource_id); 199 200 // Gets an image resource from the current module data. This will load the 201 // image in Skia format by default. The ResourceBundle owns this. 202 gfx::Image& GetImageNamed(int resource_id); 203 204 // Similar to GetImageNamed, but rather than loading the image in Skia format, 205 // it will load in the native platform type. This can avoid conversion from 206 // one image type to another. ResourceBundle owns the result. 207 // 208 // Note that if the same resource has already been loaded in GetImageNamed(), 209 // gfx::Image will perform a conversion, rather than using the native image 210 // loading code of ResourceBundle. 211 // 212 // If |rtl| is RTL_ENABLED then the image is flipped in RTL locales. 213 gfx::Image& GetNativeImageNamed(int resource_id, ImageRTL rtl); 214 215 // Same as GetNativeImageNamed() except that RTL is not enabled. 216 gfx::Image& GetNativeImageNamed(int resource_id); 217 218 // Loads the raw bytes of a scale independent data resource. 219 base::RefCountedStaticMemory* LoadDataResourceBytes(int resource_id) const; 220 221 // Loads the raw bytes of a data resource nearest the scale factor 222 // |scale_factor| into |bytes|, without doing any processing or 223 // interpretation of the resource. Use ResourceHandle::SCALE_FACTOR_NONE 224 // for scale independent image resources (such as wallpaper). 225 // Returns NULL if we fail to read the resource. 226 base::RefCountedStaticMemory* LoadDataResourceBytesForScale( 227 int resource_id, 228 ScaleFactor scale_factor) const; 229 230 // Return the contents of a scale independent resource in a 231 // StringPiece given the resource id 232 base::StringPiece GetRawDataResource(int resource_id) const; 233 234 // Return the contents of a resource in a StringPiece given the resource id 235 // nearest the scale factor |scale_factor|. 236 // Use ResourceHandle::SCALE_FACTOR_NONE for scale independent image resources 237 // (such as wallpaper). 238 base::StringPiece GetRawDataResourceForScale(int resource_id, 239 ScaleFactor scale_factor) const; 240 241 // Get a localized string given a message id. Returns an empty 242 // string if the message_id is not found. 243 base::string16 GetLocalizedString(int message_id); 244 245 // Returns the font list for the specified style. 246 const gfx::FontList& GetFontList(FontStyle style); 247 248 // Returns the font for the specified style. 249 const gfx::Font& GetFont(FontStyle style); 250 251 // Resets and reloads the cached fonts. This is useful when the fonts of the 252 // system have changed, for example, when the locale has changed. 253 void ReloadFonts(); 254 255 // Overrides the path to the pak file from which the locale resources will be 256 // loaded. Pass an empty path to undo. 257 void OverrideLocalePakForTest(const base::FilePath& pak_path); 258 259 // Overrides a localized string resource with the given string. If no delegate 260 // is present, the |string| will be returned when getting the localized string 261 // |message_id|. If |ReloadLocaleResources| is called, all overrides are 262 // cleared. This is intended to be used in conjunction with field trials and 263 // the variations service to experiment with different UI strings. This method 264 // is not thread safe! 265 void OverrideLocaleStringResource(int message_id, 266 const base::string16& string); 267 268 // Returns the full pathname of the locale file to load. May return an empty 269 // string if no locale data files are found and |test_file_exists| is true. 270 // Used on Android to load the local file in the browser process and pass it 271 // to the sandboxed renderer process. 272 base::FilePath GetLocaleFilePath(const std::string& app_locale, 273 bool test_file_exists); 274 275 // Returns the maximum scale factor currently loaded. 276 // Returns SCALE_FACTOR_100P if no resource is loaded. 277 ScaleFactor GetMaxScaleFactor() const; 278 279 protected: 280 // Returns true if |scale_factor| is supported by this platform. 281 static bool IsScaleFactorSupported(ScaleFactor scale_factor); 282 283 private: 284 FRIEND_TEST_ALL_PREFIXES(ResourceBundleTest, DelegateGetPathForLocalePack); 285 FRIEND_TEST_ALL_PREFIXES(ResourceBundleTest, DelegateGetImageNamed); 286 FRIEND_TEST_ALL_PREFIXES(ResourceBundleTest, DelegateGetNativeImageNamed); 287 288 friend class ResourceBundleImageTest; 289 friend class ResourceBundleTest; 290 291 class ResourceBundleImageSource; 292 friend class ResourceBundleImageSource; 293 294 typedef base::hash_map<int, base::string16> IdToStringMap; 295 296 // Ctor/dtor are private, since we're a singleton. 297 explicit ResourceBundle(Delegate* delegate); 298 ~ResourceBundle(); 299 300 // Shared initialization. 301 static void InitSharedInstance(Delegate* delegate); 302 303 // Free skia_images_. 304 void FreeImages(); 305 306 // Load the main resources. 307 void LoadCommonResources(); 308 309 // Implementation for AddDataPackFromPath and AddOptionalDataPackFromPath, if 310 // the pack is not |optional| logs an error on failure to load. 311 void AddDataPackFromPathInternal(const base::FilePath& path, 312 ScaleFactor scale_factor, 313 bool optional); 314 315 // Inserts |data_pack| to |data_pack_| and updates |max_scale_factor_| 316 // accordingly. 317 void AddDataPack(DataPack* data_pack); 318 319 // Try to load the locale specific strings from an external data module. 320 // Returns the locale that is loaded. 321 std::string LoadLocaleResources(const std::string& pref_locale); 322 323 // Load test resources in given paths. If either path is empty an empty 324 // resource pack is loaded. 325 void LoadTestResources(const base::FilePath& path, 326 const base::FilePath& locale_path); 327 328 // Unload the locale specific strings and prepares to load new ones. See 329 // comments for ReloadLocaleResources(). 330 void UnloadLocaleResources(); 331 332 // Initializes all the gfx::FontList members if they haven't yet been 333 // initialized. 334 void LoadFontsIfNecessary(); 335 336 // Returns a FontList or NULL by calling Delegate::GetFont and converting 337 // scoped_ptr<gfx::Font> to scoped_ptr<gfx::FontList>. 338 scoped_ptr<gfx::FontList> GetFontListFromDelegate(FontStyle style); 339 340 // Fills the |bitmap| given the data file to look in and the |resource_id|. 341 // Returns false if the resource does not exist. 342 // 343 // If the call succeeds, |fell_back_to_1x| indicates whether Chrome's custom 344 // csCl PNG chunk is present (added by GRIT if it falls back to a 100% image). 345 bool LoadBitmap(const ResourceHandle& data_handle, 346 int resource_id, 347 SkBitmap* bitmap, 348 bool* fell_back_to_1x) const; 349 350 // Fills the |bitmap| given the |resource_id| and |scale_factor|. 351 // Returns false if the resource does not exist. This may fall back to 352 // the data pack with SCALE_FACTOR_NONE, and when this happens, 353 // |scale_factor| will be set to SCALE_FACTOR_100P. 354 bool LoadBitmap(int resource_id, 355 ScaleFactor* scale_factor, 356 SkBitmap* bitmap, 357 bool* fell_back_to_1x) const; 358 359 // Returns true if missing scaled resources should be visually indicated when 360 // drawing the fallback (e.g., by tinting the image). 361 static bool ShouldHighlightMissingScaledResources(); 362 363 // Returns true if the data in |buf| is a PNG that has the special marker 364 // added by GRIT that indicates that the image is actually 1x data. 365 static bool PNGContainsFallbackMarker(const unsigned char* buf, size_t size); 366 367 // A wrapper for PNGCodec::Decode that returns information about custom 368 // chunks. For security reasons we can't alter PNGCodec to return this 369 // information. Our PNG files are preprocessed by GRIT, and any special chunks 370 // should occur immediately after the IHDR chunk. 371 static bool DecodePNG(const unsigned char* buf, 372 size_t size, 373 SkBitmap* bitmap, 374 bool* fell_back_to_1x); 375 376 // Returns an empty image for when a resource cannot be loaded. This is a 377 // bright red bitmap. 378 gfx::Image& GetEmptyImage(); 379 380 const base::FilePath& GetOverriddenPakPath(); 381 382 // This pointer is guaranteed to outlive the ResourceBundle instance and may 383 // be NULL. 384 Delegate* delegate_; 385 386 // Protects |images_| and font-related members. 387 scoped_ptr<base::Lock> images_and_fonts_lock_; 388 389 // Protects |locale_resources_data_|. 390 scoped_ptr<base::Lock> locale_resources_data_lock_; 391 392 // Handles for data sources. 393 scoped_ptr<ResourceHandle> locale_resources_data_; 394 ScopedVector<ResourceHandle> data_packs_; 395 396 // The maximum scale factor currently loaded. 397 ScaleFactor max_scale_factor_; 398 399 // Cached images. The ResourceBundle caches all retrieved images and keeps 400 // ownership of the pointers. 401 typedef std::map<int, gfx::Image> ImageMap; 402 ImageMap images_; 403 404 gfx::Image empty_image_; 405 406 // The various font lists used. Cached to avoid repeated GDI 407 // creation/destruction. 408 scoped_ptr<gfx::FontList> base_font_list_; 409 scoped_ptr<gfx::FontList> bold_font_list_; 410 scoped_ptr<gfx::FontList> small_font_list_; 411 scoped_ptr<gfx::FontList> small_bold_font_list_; 412 scoped_ptr<gfx::FontList> medium_font_list_; 413 scoped_ptr<gfx::FontList> medium_bold_font_list_; 414 scoped_ptr<gfx::FontList> large_font_list_; 415 scoped_ptr<gfx::FontList> large_bold_font_list_; 416 scoped_ptr<gfx::FontList> web_font_list_; 417 418 base::FilePath overridden_pak_path_; 419 420 IdToStringMap overridden_locale_strings_; 421 422 DISALLOW_COPY_AND_ASSIGN(ResourceBundle); 423 }; 424 425 } // namespace ui 426 427 // TODO(beng): Someday, maybe, get rid of this. 428 using ui::ResourceBundle; 429 430 #endif // UI_BASE_RESOURCE_RESOURCE_BUNDLE_H_ 431