// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "chrome/common/resource_bundle.h" #include #include "base/file_util.h" #include "base/gfx/png_decoder.h" #include "base/logging.h" #include "base/path_service.h" #include "base/resource_util.h" #include "base/scoped_ptr.h" #include "base/string_piece.h" #include "base/string_util.h" #include "base/win_util.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/gfx/chrome_font.h" #include "chrome/common/l10n_util.h" #include "chrome/common/win_util.h" #include "SkBitmap.h" using namespace std; ResourceBundle *ResourceBundle::g_shared_instance_ = NULL; // Returns the flags that should be passed to LoadLibraryEx. DWORD GetDataDllLoadFlags() { if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) return LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE; return 0; } /* static */ void ResourceBundle::InitSharedInstance(const std::wstring& pref_locale) { DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; g_shared_instance_ = new ResourceBundle(); g_shared_instance_->LoadLocaleResources(pref_locale); } /* static */ void ResourceBundle::CleanupSharedInstance() { if (g_shared_instance_) { delete g_shared_instance_; g_shared_instance_ = NULL; } } /* static */ ResourceBundle& ResourceBundle::GetSharedInstance() { // Must call InitSharedInstance before this function. CHECK(g_shared_instance_ != NULL); return *g_shared_instance_; } ResourceBundle::ResourceBundle() : locale_resources_dll_(NULL), theme_dll_(NULL) { } ResourceBundle::~ResourceBundle() { for (SkImageMap::iterator i = skia_images_.begin(); i != skia_images_.end(); i++) { delete i->second; } skia_images_.clear(); if (locale_resources_dll_) { BOOL rv = FreeLibrary(locale_resources_dll_); DCHECK(rv); } if (theme_dll_) { BOOL rv = FreeLibrary(theme_dll_); DCHECK(rv); } } void ResourceBundle::LoadLocaleResources(const std::wstring& pref_locale) { DCHECK(NULL == locale_resources_dll_) << "locale dll already loaded"; const std::wstring& locale_path = GetLocaleDllPath(pref_locale); if (locale_path.empty()) { // It's possible that there are no locale dlls found, in which case we just // return. NOTREACHED(); return; } // The dll should only have resources, not executable code. locale_resources_dll_ = LoadLibraryEx(locale_path.c_str(), NULL, GetDataDllLoadFlags()); DCHECK(locale_resources_dll_ != NULL) << "unable to load generated resources"; } std::wstring ResourceBundle::GetLocaleDllPath(const std::wstring& pref_locale) { std::wstring locale_path; PathService::Get(chrome::DIR_LOCALES, &locale_path); const std::wstring app_locale = l10n_util::GetApplicationLocale(pref_locale); if (app_locale.empty()) return app_locale; file_util::AppendToPath(&locale_path, app_locale + L".dll"); return locale_path; } void ResourceBundle::LoadThemeResources() { DCHECK(NULL == theme_dll_) << "theme dll already loaded"; std::wstring theme_dll_path; PathService::Get(chrome::DIR_THEMES, &theme_dll_path); file_util::AppendToPath(&theme_dll_path, L"default.dll"); // The dll should only have resources, not executable code. theme_dll_ = LoadLibraryEx(theme_dll_path.c_str(), NULL, GetDataDllLoadFlags()); DCHECK(theme_dll_ != NULL) << "unable to load " << theme_dll_path; } /* static */ SkBitmap* ResourceBundle::LoadBitmap(HINSTANCE dll_inst, int resource_id) { void* data_ptr = NULL; size_t data_size; bool success = base::GetDataResourceFromModule(dll_inst, resource_id, &data_ptr, &data_size); if (!success) return NULL; unsigned char* data = static_cast(data_ptr); // Decode the PNG. vector png_data; int image_width; int image_height; if (!PNGDecoder::Decode(data, data_size, PNGDecoder::FORMAT_BGRA, &png_data, &image_width, &image_height)) { NOTREACHED() << "Unable to decode theme resource " << resource_id; return NULL; } return PNGDecoder::CreateSkBitmapFromBGRAFormat(png_data, image_width, image_height); } SkBitmap* ResourceBundle::GetBitmapNamed(int resource_id) { AutoLock lock_scope(lock_); SkImageMap::const_iterator found = skia_images_.find(resource_id); SkBitmap* bitmap = NULL; // If not found load and store the image if (found == skia_images_.end()) { // Load the image bitmap = LoadBitmap(theme_dll_, resource_id); // We did not find the bitmap in the theme DLL, try the current one. if (!bitmap) bitmap = LoadBitmap(_AtlBaseModule.GetModuleInstance(), resource_id); skia_images_[resource_id] = bitmap; } else { bitmap = found->second; } // This bitmap will be returned when a bitmap is requested that can not be // found. The data inside is lazily initialized, so users must lock and static SkBitmap* empty_bitmap = NULL; // Handle the case where loading the bitmap failed. if (!bitmap) { LOG(WARNING) << "Unable to load bitmap with id " << resource_id; if (!empty_bitmap) { empty_bitmap = new SkBitmap(); } return empty_bitmap; } return bitmap; } bool ResourceBundle::LoadImageResourceBytes(int resource_id, vector* bytes) { return LoadModuleResourceBytes(theme_dll_, resource_id, bytes); } bool ResourceBundle::LoadDataResourceBytes(int resource_id, vector* bytes) { return LoadModuleResourceBytes(_AtlBaseModule.GetModuleInstance(), resource_id, bytes); } bool ResourceBundle::LoadModuleResourceBytes( HINSTANCE module, int resource_id, std::vector* bytes) { void* data_ptr; size_t data_size; if (base::GetDataResourceFromModule(module, resource_id, &data_ptr, &data_size)) { bytes->resize(data_size); memcpy(&(bytes->front()), data_ptr, data_size); return true; } else { return false; } } HICON ResourceBundle::LoadThemeIcon(int icon_id) { return ::LoadIcon(theme_dll_, MAKEINTRESOURCE(icon_id)); } std::string ResourceBundle::GetDataResource(int resource_id) { return GetRawDataResource(resource_id).as_string(); } StringPiece ResourceBundle::GetRawDataResource(int resource_id) { void* data_ptr; size_t data_size; if (base::GetDataResourceFromModule( _AtlBaseModule.GetModuleInstance(), resource_id, &data_ptr, &data_size)) return StringPiece(static_cast(data_ptr), data_size); return StringPiece(); } // Loads and returns the global accelerators from the current module. HACCEL ResourceBundle::GetGlobalAccelerators() { return ::LoadAccelerators(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCE(IDR_MAINFRAME)); } // Loads and returns a cursor from the current module. HCURSOR ResourceBundle::LoadCursor(int cursor_id) { return ::LoadCursor(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCE(cursor_id)); } std::wstring ResourceBundle::GetLocalizedString(int message_id) { // If for some reason we were unable to load a resource dll, return an empty // string (better than crashing). if (!locale_resources_dll_) return std::wstring(); DCHECK(IS_INTRESOURCE(message_id)); // Get a reference directly to the string resource. HINSTANCE hinstance = locale_resources_dll_; const ATLSTRINGRESOURCEIMAGE* image = AtlGetStringResourceImage(hinstance, message_id); if (!image) { // Fall back on the current module (shouldn't be any strings here except // in unittests). image = AtlGetStringResourceImage(_AtlBaseModule.GetModuleInstance(), message_id); if (!image) { NOTREACHED() << "unable to find resource: " << message_id; return std::wstring(); } } // Copy into a wstring and return. return std::wstring(image->achString, image->nLength); } void ResourceBundle::LoadFontsIfNecessary() { AutoLock lock_scope(lock_); if (!base_font_.get()) { base_font_.reset(new ChromeFont()); small_font_.reset(new ChromeFont()); *small_font_ = base_font_->DeriveFont(-2); medium_font_.reset(new ChromeFont()); *medium_font_ = base_font_->DeriveFont(3); medium_bold_font_.reset(new ChromeFont()); *medium_bold_font_ = base_font_->DeriveFont(3, base_font_->style() | ChromeFont::BOLD); large_font_.reset(new ChromeFont()); *large_font_ = base_font_->DeriveFont(8); web_font_.reset(new ChromeFont()); *web_font_ = base_font_->DeriveFont(1, base_font_->style() | ChromeFont::WEB); } } ChromeFont ResourceBundle::GetFont(FontStyle style) { LoadFontsIfNecessary(); switch(style) { case SmallFont: return *small_font_; case MediumFont: return *medium_font_; case MediumBoldFont: return *medium_bold_font_; case LargeFont: return *large_font_; case WebFont: return *web_font_; default: return *base_font_; } }