diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/DEPS | 1 | ||||
-rw-r--r-- | ui/README.chromium | 16 | ||||
-rw-r--r-- | ui/base/resource/data_pack.cc | 219 | ||||
-rw-r--r-- | ui/base/resource/data_pack.h | 65 | ||||
-rw-r--r-- | ui/base/resource/data_pack_unittest.cc | 76 | ||||
-rw-r--r-- | ui/base/resource/resource_bundle.cc | 269 | ||||
-rw-r--r-- | ui/base/resource/resource_bundle.h | 283 | ||||
-rw-r--r-- | ui/base/resource/resource_bundle_dummy.cc | 67 | ||||
-rw-r--r-- | ui/base/resource/resource_bundle_linux.cc | 148 | ||||
-rw-r--r-- | ui/base/resource/resource_bundle_mac.mm | 72 | ||||
-rw-r--r-- | ui/base/resource/resource_bundle_posix.cc | 121 | ||||
-rw-r--r-- | ui/base/resource/resource_bundle_win.cc | 170 | ||||
-rw-r--r-- | ui/base/test/data/data_pack_unittest/sample.pak | bin | 0 -> 80 bytes | |||
-rw-r--r-- | ui/base/test/data/resource.h | 28 | ||||
-rw-r--r-- | ui/base/ui_base_paths.cc | 75 | ||||
-rw-r--r-- | ui/base/ui_base_paths.h | 33 | ||||
-rw-r--r-- | ui/base/ui_base_switches.cc | 13 | ||||
-rw-r--r-- | ui/base/ui_base_switches.h | 17 |
18 files changed, 1673 insertions, 0 deletions
@@ -1,6 +1,7 @@ include_rules = [ "+gfx", "+net", + "+skia", "+third_party/mozilla", # Temporary until all of src/app is consumed into src/ui diff --git a/ui/README.chromium b/ui/README.chromium new file mode 100644 index 0000000..3279ad9 --- /dev/null +++ b/ui/README.chromium @@ -0,0 +1,16 @@ +This directory contains elements of Chromium's user interface toolkit:
+
+base/
+ Common UI framework components for resource loading, localization,
+ string formatting, cross platform model interfaces etc.
+views/
+ UI "View" framework used for building interfaces on Windows and Linux
+ (ChromeOS).
+
+This directory is NOT for things that are unrelated to a user interface library,
+even if:
+* they are shared by multiple top level directories in src/,
+* brettw won't let you put them in base!
+* it's just two little files... come on!
+
+- ben@chromium.org
diff --git a/ui/base/resource/data_pack.cc b/ui/base/resource/data_pack.cc new file mode 100644 index 0000000..f1cedcc --- /dev/null +++ b/ui/base/resource/data_pack.cc @@ -0,0 +1,219 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/resource/data_pack.h" + +#include <errno.h> + +#include "base/file_util.h" +#include "base/logging.h" +#include "base/metrics/histogram.h" +#include "base/ref_counted_memory.h" +#include "base/string_piece.h" + +// For details of the file layout, see +// http://dev.chromium.org/developers/design-documents/linuxresourcesandlocalizedstrings + +namespace { + +// A word is four bytes. +static const size_t kWord = 4; + +static const uint32 kFileFormatVersion = 1; +// Length of file header: version and entry count. +static const size_t kHeaderLength = 2 * sizeof(uint32); + +struct DataPackEntry { + uint32 resource_id; + uint32 file_offset; + uint32 length; + + static int CompareById(const void* void_key, const void* void_entry) { + uint32 key = *reinterpret_cast<const uint32*>(void_key); + const DataPackEntry* entry = + reinterpret_cast<const DataPackEntry*>(void_entry); + if (key < entry->resource_id) { + return -1; + } else if (key > entry->resource_id) { + return 1; + } else { + return 0; + } + } +}; + +COMPILE_ASSERT(sizeof(DataPackEntry) == 12, size_of_header_must_be_twelve); + +// We're crashing when trying to load a pak file on Windows. Add some error +// codes for logging. +// http://crbug.com/58056 +enum LoadErrors { + INIT_FAILED = 1, + BAD_VERSION, + INDEX_TRUNCATED, + ENTRY_NOT_FOUND, + + LOAD_ERRORS_COUNT, +}; + +} // namespace + +namespace ui { + +// In .cc for MemoryMappedFile dtor. +DataPack::DataPack() : resource_count_(0) { +} +DataPack::~DataPack() { +} + +bool DataPack::Load(const FilePath& path) { + mmap_.reset(new file_util::MemoryMappedFile); + if (!mmap_->Initialize(path)) { + DLOG(ERROR) << "Failed to mmap datapack"; + UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INIT_FAILED, + LOAD_ERRORS_COUNT); + return false; + } + + // Parse the header of the file. + // First uint32: version; second: resource count. + const uint32* ptr = reinterpret_cast<const uint32*>(mmap_->data()); + uint32 version = ptr[0]; + if (version != kFileFormatVersion) { + LOG(ERROR) << "Bad data pack version: got " << version << ", expected " + << kFileFormatVersion; + UMA_HISTOGRAM_ENUMERATION("DataPack.Load", BAD_VERSION, + LOAD_ERRORS_COUNT); + mmap_.reset(); + return false; + } + resource_count_ = ptr[1]; + + // Sanity check the file. + // 1) Check we have enough entries. + if (kHeaderLength + resource_count_ * sizeof(DataPackEntry) > + mmap_->length()) { + LOG(ERROR) << "Data pack file corruption: too short for number of " + "entries specified."; + UMA_HISTOGRAM_ENUMERATION("DataPack.Load", INDEX_TRUNCATED, + LOAD_ERRORS_COUNT); + mmap_.reset(); + return false; + } + // 2) Verify the entries are within the appropriate bounds. + for (size_t i = 0; i < resource_count_; ++i) { + const DataPackEntry* entry = reinterpret_cast<const DataPackEntry*>( + mmap_->data() + kHeaderLength + (i * sizeof(DataPackEntry))); + if (entry->file_offset + entry->length > mmap_->length()) { + LOG(ERROR) << "Entry #" << i << " in data pack points off end of file. " + << "Was the file corrupted?"; + UMA_HISTOGRAM_ENUMERATION("DataPack.Load", ENTRY_NOT_FOUND, + LOAD_ERRORS_COUNT); + mmap_.reset(); + return false; + } + } + + return true; +} + +bool DataPack::GetStringPiece(uint32 resource_id, + base::StringPiece* data) const { + // It won't be hard to make this endian-agnostic, but it's not worth + // bothering to do right now. +#if defined(__BYTE_ORDER) + // Linux check + COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, + datapack_assumes_little_endian); +#elif defined(__BIG_ENDIAN__) + // Mac check + #error DataPack assumes little endian +#endif + + DataPackEntry* target = reinterpret_cast<DataPackEntry*>( + bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_, + sizeof(DataPackEntry), DataPackEntry::CompareById)); + if (!target) { + return false; + } + + data->set(mmap_->data() + target->file_offset, target->length); + return true; +} + +RefCountedStaticMemory* DataPack::GetStaticMemory(uint32 resource_id) const { + base::StringPiece piece; + if (!GetStringPiece(resource_id, &piece)) + return NULL; + + return new RefCountedStaticMemory( + reinterpret_cast<const unsigned char*>(piece.data()), piece.length()); +} + +// static +bool DataPack::WritePack(const FilePath& path, + const std::map<uint32, base::StringPiece>& resources) { + FILE* file = file_util::OpenFile(path, "wb"); + if (!file) + return false; + + if (fwrite(&kFileFormatVersion, 1, kWord, file) != kWord) { + LOG(ERROR) << "Failed to write file version"; + file_util::CloseFile(file); + return false; + } + + // Note: the python version of this function explicitly sorted keys, but + // std::map is a sorted associative container, we shouldn't have to do that. + uint32 entry_count = resources.size(); + if (fwrite(&entry_count, 1, kWord, file) != kWord) { + LOG(ERROR) << "Failed to write entry count"; + file_util::CloseFile(file); + return false; + } + + // Each entry is 3 uint32s. + uint32 index_length = entry_count * 3 * kWord; + uint32 data_offset = kHeaderLength + index_length; + for (std::map<uint32, base::StringPiece>::const_iterator it = + resources.begin(); + it != resources.end(); ++it) { + if (fwrite(&it->first, 1, kWord, file) != kWord) { + LOG(ERROR) << "Failed to write id for " << it->first; + file_util::CloseFile(file); + return false; + } + + if (fwrite(&data_offset, 1, kWord, file) != kWord) { + LOG(ERROR) << "Failed to write offset for " << it->first; + file_util::CloseFile(file); + return false; + } + + uint32 len = it->second.length(); + if (fwrite(&len, 1, kWord, file) != kWord) { + LOG(ERROR) << "Failed to write length for " << it->first; + file_util::CloseFile(file); + return false; + } + + data_offset += len; + } + + for (std::map<uint32, base::StringPiece>::const_iterator it = + resources.begin(); + it != resources.end(); ++it) { + if (fwrite(it->second.data(), it->second.length(), 1, file) != 1) { + LOG(ERROR) << "Failed to write data for " << it->first; + file_util::CloseFile(file); + return false; + } + } + + file_util::CloseFile(file); + + return true; +} + +} // namespace ui diff --git a/ui/base/resource/data_pack.h b/ui/base/resource/data_pack.h new file mode 100644 index 0000000..2f890c6 --- /dev/null +++ b/ui/base/resource/data_pack.h @@ -0,0 +1,65 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// DataPack represents a read-only view onto an on-disk file that contains +// (key, value) pairs of data. It's used to store static resources like +// translation strings and images. + +#ifndef UI_BASE_RESOURCE_DATA_PACK_H_ +#define UI_BASE_RESOURCE_DATA_PACK_H_ +#pragma once + +#include <map> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" + +class FilePath; +class RefCountedStaticMemory; + +namespace base { +class StringPiece; +} + +namespace file_util { +class MemoryMappedFile; +} + +namespace ui { + +class DataPack { + public: + DataPack(); + ~DataPack(); + + // Load a pack file from |path|, returning false on error. + bool Load(const FilePath& path); + + // Get resource by id |resource_id|, filling in |data|. + // The data is owned by the DataPack object and should not be modified. + // Returns false if the resource id isn't found. + bool GetStringPiece(uint32 resource_id, base::StringPiece* data) const; + + // Like GetStringPiece(), but returns a reference to memory. This interface + // is used for image data, while the StringPiece interface is usually used + // for localization strings. + RefCountedStaticMemory* GetStaticMemory(uint32 resource_id) const; + + // Writes a pack file containing |resources| to |path|. + static bool WritePack(const FilePath& path, + const std::map<uint32, base::StringPiece>& resources); + + private: + // The memory-mapped data. + scoped_ptr<file_util::MemoryMappedFile> mmap_; + + // Number of resources in the data. + size_t resource_count_; + + DISALLOW_COPY_AND_ASSIGN(DataPack); +}; + +} // namespace ui + +#endif // UI_BASE_RESOURCE_DATA_PACK_H_ diff --git a/ui/base/resource/data_pack_unittest.cc b/ui/base/resource/data_pack_unittest.cc new file mode 100644 index 0000000..fb15a07 --- /dev/null +++ b/ui/base/resource/data_pack_unittest.cc @@ -0,0 +1,76 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/scoped_temp_dir.h" +#include "base/string_piece.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/resource/data_pack.h" + +namespace ui { + +TEST(DataPackTest, Load) { + FilePath data_path; + PathService::Get(base::DIR_SOURCE_ROOT, &data_path); + data_path = data_path.Append( + FILE_PATH_LITERAL("app/test/data/data_pack_unittest/sample.pak")); + + DataPack pack; + ASSERT_TRUE(pack.Load(data_path)); + + base::StringPiece data; + ASSERT_TRUE(pack.GetStringPiece(4, &data)); + EXPECT_EQ("this is id 4", data); + ASSERT_TRUE(pack.GetStringPiece(6, &data)); + EXPECT_EQ("this is id 6", data); + + // Try reading zero-length data blobs, just in case. + ASSERT_TRUE(pack.GetStringPiece(1, &data)); + EXPECT_EQ(0U, data.length()); + ASSERT_TRUE(pack.GetStringPiece(10, &data)); + EXPECT_EQ(0U, data.length()); + + // Try looking up an invalid key. + ASSERT_FALSE(pack.GetStringPiece(140, &data)); +} + +TEST(DataPackTest, Write) { + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + FilePath file = dir.path().Append(FILE_PATH_LITERAL("data.pak")); + + std::string one("one"); + std::string two("two"); + std::string three("three"); + std::string four("four"); + std::string fifteen("fifteen"); + + std::map<uint32, base::StringPiece> resources; + resources.insert(std::make_pair(1, base::StringPiece(one))); + resources.insert(std::make_pair(2, base::StringPiece(two))); + resources.insert(std::make_pair(15, base::StringPiece(fifteen))); + resources.insert(std::make_pair(3, base::StringPiece(three))); + resources.insert(std::make_pair(4, base::StringPiece(four))); + ASSERT_TRUE(DataPack::WritePack(file, resources)); + + // Now try to read the data back in. + DataPack pack; + ASSERT_TRUE(pack.Load(file)); + + base::StringPiece data; + ASSERT_TRUE(pack.GetStringPiece(1, &data)); + EXPECT_EQ(one, data); + ASSERT_TRUE(pack.GetStringPiece(2, &data)); + EXPECT_EQ(two, data); + ASSERT_TRUE(pack.GetStringPiece(3, &data)); + EXPECT_EQ(three, data); + ASSERT_TRUE(pack.GetStringPiece(4, &data)); + EXPECT_EQ(four, data); + ASSERT_TRUE(pack.GetStringPiece(15, &data)); + EXPECT_EQ(fifteen, data); +} + +} // namespace ui diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc new file mode 100644 index 0000000..94885b0 --- /dev/null +++ b/ui/base/resource/resource_bundle.cc @@ -0,0 +1,269 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/resource/resource_bundle.h" + +#include "base/lock.h" +#include "base/logging.h" +#include "base/stl_util-inl.h" +#include "base/string_piece.h" +#include "build/build_config.h" +#include "gfx/codec/png_codec.h" +#include "gfx/font.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/resource/data_pack.h" + +namespace ui { + +namespace { + +// Font sizes relative to base font. +#if defined(OS_CHROMEOS) && defined(CROS_FONTS_USING_BCI) +const int kSmallFontSizeDelta = -3; +const int kMediumFontSizeDelta = 2; +const int kLargeFontSizeDelta = 7; +#else +const int kSmallFontSizeDelta = -2; +const int kMediumFontSizeDelta = 3; +const int kLargeFontSizeDelta = 8; +#endif + +} // namespace + +ResourceBundle* ResourceBundle::g_shared_instance_ = NULL; + +/* static */ +// TODO(glen): Finish moving these into theme provider (dialogs still +// depend on these colors). +const SkColor ResourceBundle::frame_color = + SkColorSetRGB(66, 116, 201); +const SkColor ResourceBundle::frame_color_inactive = + SkColorSetRGB(161, 182, 228); +const SkColor ResourceBundle::frame_color_app_panel = + SK_ColorWHITE; +const SkColor ResourceBundle::frame_color_app_panel_inactive = + SK_ColorWHITE; +const SkColor ResourceBundle::frame_color_incognito = + SkColorSetRGB(83, 106, 139); +const SkColor ResourceBundle::frame_color_incognito_inactive = + SkColorSetRGB(126, 139, 156); +const SkColor ResourceBundle::toolbar_color = + SkColorSetRGB(210, 225, 246); +const SkColor ResourceBundle::toolbar_separator_color = + SkColorSetRGB(182, 186, 192); + +/* static */ +std::string ResourceBundle::InitSharedInstance( + const std::string& pref_locale) { + DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; + g_shared_instance_ = new ResourceBundle(); + + g_shared_instance_->LoadCommonResources(); + return g_shared_instance_->LoadLocaleResources(pref_locale); +} + +/* static */ +std::string ResourceBundle::ReloadSharedInstance( + const std::string& pref_locale) { + DCHECK(g_shared_instance_ != NULL) << "ResourceBundle not initialized"; + + g_shared_instance_->UnloadLocaleResources(); + return g_shared_instance_->LoadLocaleResources(pref_locale); +} + +/* static */ +void ResourceBundle::AddDataPackToSharedInstance(const FilePath& path) { + DCHECK(g_shared_instance_ != NULL) << "ResourceBundle not initialized"; + g_shared_instance_->data_packs_.push_back(new LoadedDataPack(path)); +} + +/* 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_; +} + +SkBitmap* ResourceBundle::GetBitmapNamed(int resource_id) { + // Check to see if we already have the Skia image in the cache. + { + AutoLock lock_scope(*lock_); + SkImageMap::const_iterator found = skia_images_.find(resource_id); + if (found != skia_images_.end()) + return found->second; + } + + scoped_ptr<SkBitmap> bitmap; + + bitmap.reset(LoadBitmap(resources_data_, resource_id)); + + if (bitmap.get()) { + // We loaded successfully. Cache the Skia version of the bitmap. + AutoLock lock_scope(*lock_); + + // Another thread raced us, and has already cached the skia image. + if (skia_images_.count(resource_id)) + return skia_images_[resource_id]; + + skia_images_[resource_id] = bitmap.get(); + return bitmap.release(); + } + + // We failed to retrieve the bitmap, show a debugging red square. + { + LOG(WARNING) << "Unable to load bitmap with id " << resource_id; + NOTREACHED(); // Want to assert in debug mode. + + AutoLock lock_scope(*lock_); // Guard empty_bitmap initialization. + + static SkBitmap* empty_bitmap = NULL; + if (!empty_bitmap) { + // The placeholder bitmap is bright red so people notice the problem. + // This bitmap will be leaked, but this code should never be hit. + empty_bitmap = new SkBitmap(); + empty_bitmap->setConfig(SkBitmap::kARGB_8888_Config, 32, 32); + empty_bitmap->allocPixels(); + empty_bitmap->eraseARGB(255, 255, 0, 0); + } + return empty_bitmap; + } +} + +RefCountedStaticMemory* ResourceBundle::LoadDataResourceBytes( + int resource_id) const { + RefCountedStaticMemory* bytes = + LoadResourceBytes(resources_data_, resource_id); + + // Check all our additional data packs for the resources if it wasn't loaded + // from our main source. + for (std::vector<LoadedDataPack*>::const_iterator it = data_packs_.begin(); + !bytes && it != data_packs_.end(); ++it) { + bytes = (*it)->GetStaticMemory(resource_id); + } + + return bytes; +} + +const gfx::Font& ResourceBundle::GetFont(FontStyle style) { + LoadFontsIfNecessary(); + switch (style) { + case BoldFont: + return *bold_font_; + case SmallFont: + return *small_font_; + case MediumFont: + return *medium_font_; + case MediumBoldFont: + return *medium_bold_font_; + case LargeFont: + return *large_font_; + default: + return *base_font_; + } +} + +gfx::NativeImage ResourceBundle::GetNativeImageNamed(int resource_id) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); +#if defined(OS_MACOSX) + return rb.GetNSImageNamed(resource_id); +#elif defined(USE_X11) && !defined(TOOLKIT_VIEWS) + return rb.GetPixbufNamed(resource_id); +#else + return rb.GetBitmapNamed(resource_id); +#endif +} + +ResourceBundle::ResourceBundle() + : lock_(new Lock), + resources_data_(NULL), + locale_resources_data_(NULL) { +} + +void ResourceBundle::FreeImages() { + STLDeleteContainerPairSecondPointers(skia_images_.begin(), + skia_images_.end()); + skia_images_.clear(); +} + +void ResourceBundle::LoadFontsIfNecessary() { + AutoLock lock_scope(*lock_); + if (!base_font_.get()) { + base_font_.reset(new gfx::Font()); + + bold_font_.reset(new gfx::Font()); + *bold_font_ = + base_font_->DeriveFont(0, base_font_->GetStyle() | gfx::Font::BOLD); + + small_font_.reset(new gfx::Font()); + *small_font_ = base_font_->DeriveFont(kSmallFontSizeDelta); + + medium_font_.reset(new gfx::Font()); + *medium_font_ = base_font_->DeriveFont(kMediumFontSizeDelta); + + medium_bold_font_.reset(new gfx::Font()); + *medium_bold_font_ = + base_font_->DeriveFont(kMediumFontSizeDelta, + base_font_->GetStyle() | gfx::Font::BOLD); + + large_font_.reset(new gfx::Font()); + *large_font_ = base_font_->DeriveFont(kLargeFontSizeDelta); + } +} + +/* static */ +SkBitmap* ResourceBundle::LoadBitmap(DataHandle data_handle, int resource_id) { + scoped_refptr<RefCountedMemory> memory( + LoadResourceBytes(data_handle, resource_id)); + if (!memory) + return NULL; + + SkBitmap bitmap; + if (!gfx::PNGCodec::Decode(memory->front(), memory->size(), &bitmap)) { + NOTREACHED() << "Unable to decode theme image resource " << resource_id; + return NULL; + } + + return new SkBitmap(bitmap); +} + + +// LoadedDataPack ------------------------------------------------------------- + +ResourceBundle::LoadedDataPack::LoadedDataPack(const FilePath& path) + : path_(path) { + // Always preload the data packs so we can maintain constness. + Load(); +} + +ResourceBundle::LoadedDataPack::~LoadedDataPack() { +} + +void ResourceBundle::LoadedDataPack::Load() { + DCHECK(!data_pack_.get()); + data_pack_.reset(new ui::DataPack); + bool success = data_pack_->Load(path_); + LOG_IF(ERROR, !success) << "Failed to load " << path_.value() + << "\nYou will not be able to use the Bookmarks Manager or " + << "about:net-internals."; +} + +bool ResourceBundle::LoadedDataPack::GetStringPiece( + int resource_id, base::StringPiece* data) const { + return data_pack_->GetStringPiece(static_cast<uint32>(resource_id), data); +} + +RefCountedStaticMemory* ResourceBundle::LoadedDataPack::GetStaticMemory( + int resource_id) const { + return data_pack_->GetStaticMemory(resource_id); +} + +} // namespace ui diff --git a/ui/base/resource/resource_bundle.h b/ui/base/resource/resource_bundle.h new file mode 100644 index 0000000..9a961e2 --- /dev/null +++ b/ui/base/resource/resource_bundle.h @@ -0,0 +1,283 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_RESOURCE_RESOURCE_BUNDLE_H_ +#define UI_BASE_RESOURCE_RESOURCE_BUNDLE_H_ +#pragma once + +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <windows.h> +#endif + +#include <map> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/ref_counted_memory.h" +#include "base/scoped_ptr.h" +#include "base/string16.h" +#include "gfx/native_widget_types.h" + +class SkBitmap; +typedef uint32 SkColor; + +namespace base { +class Lock; +class StringPiece; +} + +namespace gfx { +class Font; +} + +#if defined(OS_MACOSX) +#ifdef __OBJC__ +@class NSImage; +#else +class NSImage; +#endif // __OBJC__ +#endif // defined(OS_MACOSX) + +#if defined(USE_X11) +typedef struct _GdkPixbuf GdkPixbuf; +#endif + +namespace ui { + +class DataPack; + +// ResourceBundle is a central facility to load images and other resources, +// such as theme graphics. +// Every resource is loaded only once. +class ResourceBundle { + public: + // An enumeration of the various font styles used throughout Chrome. + // The following holds true for the font sizes: + // Small <= Base <= Bold <= Medium <= MediumBold <= Large. + enum FontStyle { + SmallFont, + BaseFont, + BoldFont, + MediumFont, + // NOTE: depending upon the locale, this may *not* result in a bold font. + MediumBoldFont, + LargeFont, + }; + + // Initialize the ResourceBundle for this process. Returns the language + // selected. + // NOTE: Mac ignores this and always loads up resources for the language + // defined by the Cocoa UI (ie-NSBundle does the langange work). + static std::string InitSharedInstance(const std::string& pref_locale); + + // Changes the locale for an already-initialized ResourceBundle. Future + // calls to get strings will return the strings for this new locale. This + // has no effect on existing or future image resources. This has no effect + // on existing or future image resources, and thus does not use the lock to + // guarantee thread-safety, since all string access is expected to happen on + // the UI thread. + static std::string ReloadSharedInstance(const std::string& pref_locale); + + // Registers additional data pack files with the global ResourceBundle. When + // looking for a DataResource, we will search these files after searching the + // main module. This method is not thread safe! You should call it + // immediately after calling InitSharedInstance. + static void AddDataPackToSharedInstance(const FilePath& path); + + // Delete the ResourceBundle for this process if it exists. + static void CleanupSharedInstance(); + + // Return the global resource loader instance. + static ResourceBundle& GetSharedInstance(); + + // Gets the bitmap with the specified resource_id from the current module + // data. Returns a pointer to a shared instance of the SkBitmap. This shared + // bitmap is owned by the resource bundle and should not be freed. + SkBitmap* GetBitmapNamed(int resource_id); + + // Loads the raw bytes of a data resource into |bytes|, + // without doing any processing or interpretation of + // the resource. Returns whether we successfully read the resource. + RefCountedStaticMemory* LoadDataResourceBytes(int resource_id) const; + + // Return the contents of a resource in a StringPiece given the resource id. + base::StringPiece GetRawDataResource(int resource_id) const; + + // Get a localized string given a message id. Returns an empty + // string if the message_id is not found. + string16 GetLocalizedString(int message_id); + + // Returns the font for the specified style. + const gfx::Font& GetFont(FontStyle style); + + // Returns the gfx::NativeImage, the native platform type, named resource. + // Internally, this makes use of GetNSImageNamed(), GetPixbufNamed(), or + // GetBitmapNamed() depending on the platform (see gfx/native_widget_types.h). + // NOTE: On Mac the returned resource is autoreleased. + gfx::NativeImage GetNativeImageNamed(int resource_id); + +#if defined(OS_WIN) + // Loads and returns an icon from the app module. + HICON LoadThemeIcon(int icon_id); + + // Loads and returns a cursor from the app module. + HCURSOR LoadCursor(int cursor_id); +#elif defined(OS_MACOSX) + private: + // Wrapper for GetBitmapNamed. Converts the bitmap to an autoreleased NSImage. + // TODO(rsesek): Move implementation into GetNativeImageNamed(). + NSImage* GetNSImageNamed(int resource_id); + public: +#elif defined(USE_X11) + // Gets the GdkPixbuf with the specified resource_id from the main data pak + // file. Returns a pointer to a shared instance of the GdkPixbuf. This + // shared GdkPixbuf is owned by the resource bundle and should not be freed. + // + // The bitmap is assumed to exist. This function will log in release, and + // assert in debug mode if it does not. On failure, this will return a + // pointer to a shared empty placeholder bitmap so it will be visible what + // is missing. + GdkPixbuf* GetPixbufNamed(int resource_id); + + // As above, but flips it in RTL locales. + GdkPixbuf* GetRTLEnabledPixbufNamed(int resource_id); + + private: + // Shared implementation for the above two functions. + GdkPixbuf* GetPixbufImpl(int resource_id, bool rtl_enabled); + + public: +#endif + + // TODO(glen): Move these into theme provider (dialogs still depend on + // ResourceBundle). + static const SkColor frame_color; + static const SkColor frame_color_inactive; + static const SkColor frame_color_app_panel; + static const SkColor frame_color_app_panel_inactive; + static const SkColor frame_color_incognito; + static const SkColor frame_color_incognito_inactive; + static const SkColor toolbar_color; + static const SkColor toolbar_separator_color; + + private: + // Helper class for managing data packs. + class LoadedDataPack { + public: + explicit LoadedDataPack(const FilePath& path); + ~LoadedDataPack(); + bool GetStringPiece(int resource_id, base::StringPiece* data) const; + RefCountedStaticMemory* GetStaticMemory(int resource_id) const; + + private: + void Load(); + + scoped_ptr<DataPack> data_pack_; + FilePath path_; + + DISALLOW_COPY_AND_ASSIGN(LoadedDataPack); + }; + + // We define a DataHandle typedef to abstract across how data is stored + // across platforms. +#if defined(OS_WIN) + // Windows stores resources in DLLs, which are managed by HINSTANCE. + typedef HINSTANCE DataHandle; +#elif defined(USE_BASE_DATA_PACK) + // Linux uses base::DataPack. + typedef DataPack* DataHandle; +#endif + + // Ctor/dtor are private, since we're a singleton. + ResourceBundle(); + ~ResourceBundle(); + + // Free skia_images_. + void FreeImages(); + +#if defined(USE_X11) + // Free gdkPixbufs_. + void FreeGdkPixBufs(); +#endif + + // Load the main resources. + void LoadCommonResources(); + + // Try to load the locale specific strings from an external data module. + // Returns the locale that is loaded. + std::string LoadLocaleResources(const std::string& pref_locale); + + // Unload the locale specific strings and prepares to load new ones. See + // comments for ReloadSharedInstance(). + void UnloadLocaleResources(); + + // Initialize all the gfx::Font members if they haven't yet been initialized. + void LoadFontsIfNecessary(); + +#if defined(USE_BASE_DATA_PACK) + // Returns the full pathname of the main resources file to load. May return + // an empty string if no main resources data files are found. + static FilePath GetResourcesFilePath(); +#endif + + // Returns the full pathname of the locale file to load. May return an empty + // string if no locale data files are found. + static FilePath GetLocaleFilePath(const std::string& app_locale); + + // Returns a handle to bytes from the resource |module|, without doing any + // processing or interpretation of the resource. Returns whether we + // successfully read the resource. Caller does not own the data returned + // through this method and must not modify the data pointed to by |bytes|. + static RefCountedStaticMemory* LoadResourceBytes(DataHandle module, + int resource_id); + + // Creates and returns a new SkBitmap given the data file to look in and the + // resource id. It's up to the caller to free the returned bitmap when + // done. + static SkBitmap* LoadBitmap(DataHandle dll_inst, int resource_id); + + // Class level lock. Used to protect internal data structures that may be + // accessed from other threads (e.g., skia_images_). + scoped_ptr<base::Lock> lock_; + + // Handles for data sources. + DataHandle resources_data_; + DataHandle locale_resources_data_; + + // References to extra data packs loaded via AddDataPackToSharedInstance. + std::vector<LoadedDataPack*> data_packs_; + + // Cached images. The ResourceBundle caches all retrieved bitmaps and keeps + // ownership of the pointers. + typedef std::map<int, SkBitmap*> SkImageMap; + SkImageMap skia_images_; +#if defined(USE_X11) + typedef std::map<int, GdkPixbuf*> GdkPixbufMap; + GdkPixbufMap gdk_pixbufs_; +#endif + + // The various fonts used. Cached to avoid repeated GDI creation/destruction. + scoped_ptr<gfx::Font> base_font_; + scoped_ptr<gfx::Font> bold_font_; + scoped_ptr<gfx::Font> small_font_; + scoped_ptr<gfx::Font> medium_font_; + scoped_ptr<gfx::Font> medium_bold_font_; + scoped_ptr<gfx::Font> large_font_; + scoped_ptr<gfx::Font> web_font_; + + static ResourceBundle* g_shared_instance_; + + DISALLOW_COPY_AND_ASSIGN(ResourceBundle); +}; + +} // namespace ui + +// TODO(beng): Someday, maybe, get rid of this. +using ui::ResourceBundle; + +#endif // UI_BASE_RESOURCE_RESOURCE_BUNDLE_H_ diff --git a/ui/base/resource/resource_bundle_dummy.cc b/ui/base/resource/resource_bundle_dummy.cc new file mode 100644 index 0000000..fc46ace --- /dev/null +++ b/ui/base/resource/resource_bundle_dummy.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/resource/resource_bundle.h" + +#include <windows.h> + +#include "base/lock.h" +#include "base/logging.h" +#include "gfx/font.h" +#include "gfx/platform_font_win.h" + +// NOTE(gregoryd): This is a hack to avoid creating more nacl_win64-specific +// files. The font members of ResourceBundle are never initialized in our code +// so this destructor is never called. +namespace gfx { +Font::~Font() { + NOTREACHED(); +} +PlatformFontWin::HFontRef::~HFontRef() { + NOTREACHED(); +} +} + +namespace ui { + +ResourceBundle* ResourceBundle::g_shared_instance_ = NULL; + +/* static */ +std::string ResourceBundle::InitSharedInstance( + const std::string& pref_locale) { + DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; + g_shared_instance_ = new ResourceBundle(); + return std::string(); +} + +/* 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() + : lock_(new Lock), + resources_data_(NULL), + locale_resources_data_(NULL) { +} + +ResourceBundle::~ResourceBundle() { +} + + +string16 ResourceBundle::GetLocalizedString(int message_id) { + return string16(); +} + +} // namespace ui diff --git a/ui/base/resource/resource_bundle_linux.cc b/ui/base/resource/resource_bundle_linux.cc new file mode 100644 index 0000000..92a39df --- /dev/null +++ b/ui/base/resource/resource_bundle_linux.cc @@ -0,0 +1,148 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/resource/resource_bundle.h" + +#include <gtk/gtk.h> + +#include "base/base_paths.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/i18n/rtl.h" +#include "base/lock.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/string_piece.h" +#include "base/string_util.h" +#include "gfx/font.h" +#include "gfx/gtk_util.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/ui_base_paths.h" + +namespace ui { + +namespace { + +// Convert the raw image data into a GdkPixbuf. The GdkPixbuf that is returned +// has a ref count of 1 so the caller must call g_object_unref to free the +// memory. +GdkPixbuf* LoadPixbuf(RefCountedStaticMemory* data, bool rtl_enabled) { + ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new()); + bool ok = data && gdk_pixbuf_loader_write(loader.get(), + reinterpret_cast<const guint8*>(data->front()), data->size(), NULL); + if (!ok) + return NULL; + // Calling gdk_pixbuf_loader_close forces the data to be parsed by the + // loader. We must do this before calling gdk_pixbuf_loader_get_pixbuf. + ok = gdk_pixbuf_loader_close(loader.get(), NULL); + if (!ok) + return NULL; + GdkPixbuf* pixbuf = gdk_pixbuf_loader_get_pixbuf(loader.get()); + if (!pixbuf) + return NULL; + + if (base::i18n::IsRTL() && rtl_enabled) { + // |pixbuf| will get unreffed and destroyed (see below). The returned value + // has ref count 1. + return gdk_pixbuf_flip(pixbuf, TRUE); + } else { + // The pixbuf is owned by the loader, so add a ref so when we delete the + // loader (when the ScopedGObject goes out of scope), the pixbuf still + // exists. + g_object_ref(pixbuf); + return pixbuf; + } +} + +} // namespace + +void ResourceBundle::FreeGdkPixBufs() { + for (GdkPixbufMap::iterator i = gdk_pixbufs_.begin(); + i != gdk_pixbufs_.end(); i++) { + g_object_unref(i->second); + } + gdk_pixbufs_.clear(); +} + +// static +FilePath ResourceBundle::GetResourcesFilePath() { + FilePath resources_file_path; + PathService::Get(ui::FILE_RESOURCES_PAK, &resources_file_path); + return resources_file_path; +} + +// static +FilePath ResourceBundle::GetLocaleFilePath(const std::string& app_locale) { + FilePath locale_file_path; + PathService::Get(ui::DIR_LOCALES, &locale_file_path); + if (locale_file_path.empty()) + return locale_file_path; + if (app_locale.empty()) + return FilePath(); + locale_file_path = locale_file_path.AppendASCII(app_locale + ".pak"); + if (!file_util::PathExists(locale_file_path)) + return FilePath(); + return locale_file_path; +} + +GdkPixbuf* ResourceBundle::GetPixbufImpl(int resource_id, bool rtl_enabled) { + // Use the negative |resource_id| for the key for BIDI-aware images. + int key = rtl_enabled ? -resource_id : resource_id; + + // Check to see if we already have the pixbuf in the cache. + { + AutoLock lock_scope(*lock_); + GdkPixbufMap::const_iterator found = gdk_pixbufs_.find(key); + if (found != gdk_pixbufs_.end()) + return found->second; + } + + scoped_refptr<RefCountedStaticMemory> data( + LoadDataResourceBytes(resource_id)); + GdkPixbuf* pixbuf = LoadPixbuf(data.get(), rtl_enabled); + + // We loaded successfully. Cache the pixbuf. + if (pixbuf) { + AutoLock lock_scope(*lock_); + + // Another thread raced us, and has already cached the pixbuf. + if (gdk_pixbufs_.count(key)) { + g_object_unref(pixbuf); + return gdk_pixbufs_[key]; + } + + gdk_pixbufs_[key] = pixbuf; + return pixbuf; + } + + // We failed to retrieve the bitmap, show a debugging red square. + { + LOG(WARNING) << "Unable to load GdkPixbuf with id " << resource_id; + NOTREACHED(); // Want to assert in debug mode. + + AutoLock lock_scope(*lock_); // Guard empty_bitmap initialization. + + static GdkPixbuf* empty_bitmap = NULL; + if (!empty_bitmap) { + // The placeholder bitmap is bright red so people notice the problem. + // This bitmap will be leaked, but this code should never be hit. + scoped_ptr<SkBitmap> skia_bitmap(new SkBitmap()); + skia_bitmap->setConfig(SkBitmap::kARGB_8888_Config, 32, 32); + skia_bitmap->allocPixels(); + skia_bitmap->eraseARGB(255, 255, 0, 0); + empty_bitmap = gfx::GdkPixbufFromSkBitmap(skia_bitmap.get()); + } + return empty_bitmap; + } +} + +GdkPixbuf* ResourceBundle::GetPixbufNamed(int resource_id) { + return GetPixbufImpl(resource_id, false); +} + +GdkPixbuf* ResourceBundle::GetRTLEnabledPixbufNamed(int resource_id) { + return GetPixbufImpl(resource_id, true); +} + +} // namespace ui diff --git a/ui/base/resource/resource_bundle_mac.mm b/ui/base/resource/resource_bundle_mac.mm new file mode 100644 index 0000000..e859b1c --- /dev/null +++ b/ui/base/resource/resource_bundle_mac.mm @@ -0,0 +1,72 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/resource/resource_bundle.h" + +#import <Foundation/Foundation.h> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/mac/mac_util.h" +#include "base/sys_string_conversions.h" +#include "skia/ext/skia_utils_mac.h" + +namespace ui { + +namespace { + +FilePath GetResourcesPakFilePath(NSString* name, NSString* mac_locale) { + NSString *resource_path; + // Some of the helper processes need to be able to fetch resources + // (chrome_main.cc: SubprocessNeedsResourceBundle()). Fetch the same locale + // as the already-running browser instead of using what NSBundle might pick + // based on values at helper launch time. + if ([mac_locale length]) { + resource_path = [base::mac::MainAppBundle() pathForResource:name + ofType:@"pak" + inDirectory:@"" + forLocalization:mac_locale]; + } else { + resource_path = [base::mac::MainAppBundle() pathForResource:name + ofType:@"pak"]; + } + if (!resource_path) + return FilePath(); + return FilePath([resource_path fileSystemRepresentation]); +} + +} // namespace + +// static +FilePath ResourceBundle::GetResourcesFilePath() { + return GetResourcesPakFilePath(@"chrome", nil); +} + +// static +FilePath ResourceBundle::GetLocaleFilePath(const std::string& app_locale) { + NSString* mac_locale = base::SysUTF8ToNSString(app_locale); + + // Mac OS X uses "_" instead of "-", so swap to get a Mac-style value. + mac_locale = [mac_locale stringByReplacingOccurrencesOfString:@"-" + withString:@"_"]; + + // On disk, the "en_US" resources are just "en" (http://crbug.com/25578). + if ([mac_locale isEqual:@"en_US"]) + mac_locale = @"en"; + + return GetResourcesPakFilePath(@"locale", mac_locale); +} + +NSImage* ResourceBundle::GetNSImageNamed(int resource_id) { + // Currently this doesn't make a cache holding these as NSImages because + // GetBitmapNamed has a cache, and we don't want to double cache. + SkBitmap* bitmap = GetBitmapNamed(resource_id); + if (!bitmap) + return nil; + + NSImage* nsimage = gfx::SkBitmapToNSImage(*bitmap); + return nsimage; +} + +} // namespace ui diff --git a/ui/base/resource/resource_bundle_posix.cc b/ui/base/resource/resource_bundle_posix.cc new file mode 100644 index 0000000..119d721 --- /dev/null +++ b/ui/base/resource/resource_bundle_posix.cc @@ -0,0 +1,121 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/resource/resource_bundle.h" + +#include "app/l10n_util.h" +#include "base/lock.h" +#include "base/logging.h" +#include "base/stl_util-inl.h" +#include "base/string16.h" +#include "base/string_piece.h" +#include "gfx/font.h" +#include "ui/base/resource/data_pack.h" + +namespace ui { + +namespace { + +DataPack* LoadResourcesDataPak(FilePath resources_pak_path) { + DataPack* resources_pak = new DataPack; + bool success = resources_pak->Load(resources_pak_path); + if (!success) { + delete resources_pak; + resources_pak = NULL; + } + return resources_pak; +} + +} // namespace + +ResourceBundle::~ResourceBundle() { + FreeImages(); +#if defined(OS_POSIX) && !defined(OS_MACOSX) + FreeGdkPixBufs(); +#endif + UnloadLocaleResources(); + STLDeleteContainerPointers(data_packs_.begin(), + data_packs_.end()); + delete resources_data_; + resources_data_ = NULL; +} + +void ResourceBundle::UnloadLocaleResources() { + delete locale_resources_data_; + locale_resources_data_ = NULL; +} + +// static +RefCountedStaticMemory* ResourceBundle::LoadResourceBytes( + DataHandle module, int resource_id) { + DCHECK(module); + return module->GetStaticMemory(resource_id); +} + +base::StringPiece ResourceBundle::GetRawDataResource(int resource_id) const { + DCHECK(resources_data_); + base::StringPiece data; + if (!resources_data_->GetStringPiece(resource_id, &data)) { + if (!locale_resources_data_->GetStringPiece(resource_id, &data)) { + for (size_t i = 0; i < data_packs_.size(); ++i) { + if (data_packs_[i]->GetStringPiece(resource_id, &data)) + return data; + } + + return base::StringPiece(); + } + } + return data; +} + +string16 ResourceBundle::GetLocalizedString(int message_id) { + // If for some reason we were unable to load a resource pak, return an empty + // string (better than crashing). + if (!locale_resources_data_) { + LOG(WARNING) << "locale resources are not loaded"; + return string16(); + } + + base::StringPiece data; + if (!locale_resources_data_->GetStringPiece(message_id, &data)) { + // Fall back on the main data pack (shouldn't be any strings here except in + // unittests). + data = GetRawDataResource(message_id); + if (data.empty()) { + NOTREACHED() << "unable to find resource: " << message_id; + return string16(); + } + } + + // Data pack encodes strings as UTF16. + DCHECK_EQ(data.length() % 2, 0U); + string16 msg(reinterpret_cast<const char16*>(data.data()), + data.length() / 2); + return msg; +} + +void ResourceBundle::LoadCommonResources() { + DCHECK(!resources_data_) << "chrome.pak already loaded"; + FilePath resources_file_path = GetResourcesFilePath(); + CHECK(!resources_file_path.empty()) << "chrome.pak not found"; + resources_data_ = LoadResourcesDataPak(resources_file_path); + CHECK(resources_data_) << "failed to load chrome.pak"; +} + +std::string ResourceBundle::LoadLocaleResources( + const std::string& pref_locale) { + DCHECK(!locale_resources_data_) << "locale.pak already loaded"; + std::string app_locale = l10n_util::GetApplicationLocale(pref_locale); + FilePath locale_file_path = GetLocaleFilePath(app_locale); + if (locale_file_path.empty()) { + // It's possible that there is no locale.pak. + NOTREACHED(); + return std::string(); + } + locale_resources_data_ = LoadResourcesDataPak(locale_file_path); + CHECK(locale_resources_data_) << "failed to load locale.pak"; + return app_locale; +} + +} // namespace ui diff --git a/ui/base/resource/resource_bundle_win.cc b/ui/base/resource/resource_bundle_win.cc new file mode 100644 index 0000000..9f590d5 --- /dev/null +++ b/ui/base/resource/resource_bundle_win.cc @@ -0,0 +1,170 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/resource/resource_bundle.h" + +#include <atlbase.h> + +#include "app/l10n_util.h" +#include "base/debug/stack_trace.h" +#include "base/file_util.h" +#include "base/lock.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/resource_util.h" +#include "base/stl_util-inl.h" +#include "base/string_piece.h" +#include "base/win/windows_version.h" +#include "gfx/font.h" +#include "ui/base/ui_base_paths.h" +#include "ui/base/resource/data_pack.h" + +namespace ui { + +namespace { + +// Returns the flags that should be passed to LoadLibraryEx. +DWORD GetDataDllLoadFlags() { + if (base::win::GetVersion() >= base::win::VERSION_VISTA) + return LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE; + + return DONT_RESOLVE_DLL_REFERENCES; +} + +} // end anonymous namespace + +ResourceBundle::~ResourceBundle() { + FreeImages(); + UnloadLocaleResources(); + STLDeleteContainerPointers(data_packs_.begin(), + data_packs_.end()); + resources_data_ = NULL; +} + +void ResourceBundle::LoadCommonResources() { + // As a convenience, set resources_data_ to the current resource module. + DCHECK(NULL == resources_data_) << "common resources already loaded"; + resources_data_ = _AtlBaseModule.GetResourceInstance(); +} + +std::string ResourceBundle::LoadLocaleResources( + const std::string& pref_locale) { + DCHECK(NULL == locale_resources_data_) << "locale dll already loaded"; + const std::string app_locale = l10n_util::GetApplicationLocale(pref_locale); + const FilePath& locale_path = GetLocaleFilePath(app_locale); + if (locale_path.value().empty()) { + // It's possible that there are no locale dlls found, in which case we just + // return. + NOTREACHED(); + return std::string(); + } + + // The dll should only have resources, not executable code. + locale_resources_data_ = LoadLibraryEx(locale_path.value().c_str(), NULL, + GetDataDllLoadFlags()); + DCHECK(locale_resources_data_ != NULL) << + "unable to load generated resources"; + return app_locale; +} + +void ResourceBundle::UnloadLocaleResources() { + if (locale_resources_data_) { + BOOL rv = FreeLibrary(locale_resources_data_); + DCHECK(rv); + locale_resources_data_ = NULL; + } +} + +// static +FilePath ResourceBundle::GetLocaleFilePath(const std::string& app_locale) { + FilePath locale_path; + PathService::Get(ui::DIR_LOCALES, &locale_path); + + if (app_locale.empty()) + return FilePath(); + + return locale_path.AppendASCII(app_locale + ".dll"); +} + +// static +RefCountedStaticMemory* ResourceBundle::LoadResourceBytes( + DataHandle module, int resource_id) { + void* data_ptr; + size_t data_size; + if (base::GetDataResourceFromModule(module, resource_id, &data_ptr, + &data_size)) { + return new RefCountedStaticMemory( + reinterpret_cast<const unsigned char*>(data_ptr), data_size); + } else { + return NULL; + } +} + +HICON ResourceBundle::LoadThemeIcon(int icon_id) { + return ::LoadIcon(resources_data_, MAKEINTRESOURCE(icon_id)); +} + +base::StringPiece ResourceBundle::GetRawDataResource(int resource_id) const { + void* data_ptr; + size_t data_size; + if (base::GetDataResourceFromModule(_AtlBaseModule.GetModuleInstance(), + resource_id, + &data_ptr, + &data_size)) { + return base::StringPiece(static_cast<const char*>(data_ptr), data_size); + } else if (locale_resources_data_ && + base::GetDataResourceFromModule(locale_resources_data_, + resource_id, + &data_ptr, + &data_size)) { + return base::StringPiece(static_cast<const char*>(data_ptr), data_size); + } + + base::StringPiece data; + for (size_t i = 0; i < data_packs_.size(); ++i) { + if (data_packs_[i]->GetStringPiece(resource_id, &data)) + return data; + } + + return base::StringPiece(); +} + +// Loads and returns a cursor from the current module. +HCURSOR ResourceBundle::LoadCursor(int cursor_id) { + return ::LoadCursor(_AtlBaseModule.GetModuleInstance(), + MAKEINTRESOURCE(cursor_id)); +} + +string16 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_data_) { + base::debug::StackTrace().PrintBacktrace(); // See http://crbug.com/21925. + LOG(WARNING) << "locale resources are not loaded"; + return string16(); + } + + DCHECK(IS_INTRESOURCE(message_id)); + + // Get a reference directly to the string resource. + HINSTANCE hinstance = locale_resources_data_; + 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) { + // See http://crbug.com/21925. + base::debug::StackTrace().PrintBacktrace(); + NOTREACHED() << "unable to find resource: " << message_id; + return string16(); + } + } + // Copy into a string16 and return. + return string16(image->achString, image->nLength); +} + +} // namespace ui; diff --git a/ui/base/test/data/data_pack_unittest/sample.pak b/ui/base/test/data/data_pack_unittest/sample.pak Binary files differnew file mode 100644 index 0000000..fdbe2b5 --- /dev/null +++ b/ui/base/test/data/data_pack_unittest/sample.pak diff --git a/ui/base/test/data/resource.h b/ui/base/test/data/resource.h new file mode 100644 index 0000000..bb82442 --- /dev/null +++ b/ui/base/test/data/resource.h @@ -0,0 +1,28 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by resource.rc +// +#define IDS_SIMPLE 101 +#define IDS_PLACEHOLDERS 102 +#define IDS_PLACEHOLDERS_2 103 +#define IDS_PLACEHOLDERS_3 104 + +#define IDS_LOCALE_BOOL 105 +#define IDS_LOCALE_INT 106 +#define IDS_LOCALE_STRING 107 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 108 +#pragma once +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/ui/base/ui_base_paths.cc b/ui/base/ui_base_paths.cc new file mode 100644 index 0000000..14897f0 --- /dev/null +++ b/ui/base/ui_base_paths.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/ui_base_paths.h" + +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" + +namespace ui { + +bool PathProvider(int key, FilePath* result) { + // Assume that we will not need to create the directory if it does not exist. + // This flag can be set to true for the cases where we want to create it. + bool create_dir = false; + + FilePath cur; + switch (key) { + case ui::DIR_LOCALES: + if (!PathService::Get(base::DIR_MODULE, &cur)) + return false; +#if defined(OS_MACOSX) + // On Mac, locale files are in Contents/Resources, a sibling of the + // App dir. + cur = cur.DirName(); + cur = cur.Append(FILE_PATH_LITERAL("Resources")); +#else + cur = cur.Append(FILE_PATH_LITERAL("locales")); +#endif + create_dir = true; + break; + case ui::FILE_RESOURCES_PAK: +#if defined(OS_POSIX) && !defined(OS_MACOSX) + if (!PathService::Get(base::DIR_EXE, &cur)) + return false; + // TODO(tony): We shouldn't be referencing chrome here. + cur = cur.AppendASCII("chrome.pak"); +#else + NOTREACHED(); +#endif + break; + // The following are only valid in the development environment, and + // will fail if executed from an installed executable (because the + // generated path won't exist). + case ui::DIR_TEST_DATA: + if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur)) + return false; + cur = cur.Append(FILE_PATH_LITERAL("app")); + cur = cur.Append(FILE_PATH_LITERAL("test")); + cur = cur.Append(FILE_PATH_LITERAL("data")); + if (!file_util::PathExists(cur)) // we don't want to create this + return false; + break; + default: + return false; + } + + if (create_dir && !file_util::PathExists(cur) && + !file_util::CreateDirectory(cur)) + return false; + + *result = cur; + return true; +} + +// This cannot be done as a static initializer sadly since Visual Studio will +// eliminate this object file if there is no direct entry point into it. +void RegisterPathProvider() { + PathService::RegisterProvider(PathProvider, PATH_START, PATH_END); +} + +} // namespace ui diff --git a/ui/base/ui_base_paths.h b/ui/base/ui_base_paths.h new file mode 100644 index 0000000..3620f29 --- /dev/null +++ b/ui/base/ui_base_paths.h @@ -0,0 +1,33 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_UI_BASE_PATHS_H_ +#define UI_BASE_UI_BASE_PATHS_H_ +#pragma once + +// This file declares path keys for the app module. These can be used with +// the PathService to access various special directories and files. + +namespace ui { + +enum { + PATH_START = 3000, + + DIR_LOCALES, // Directory where locale resources are stored. + + FILE_RESOURCES_PAK, // Path to the data .pak file which holds binary + // resources. + + // Valid only in development environment; TODO(darin): move these + DIR_TEST_DATA, // Directory where unit test data resides. + + PATH_END +}; + +// Call once to register the provider for the path keys defined above. +void RegisterPathProvider(); + +} // namespace ui + +#endif // UI_BASE_UI_BASE_PATHS_H_ diff --git a/ui/base/ui_base_switches.cc b/ui/base/ui_base_switches.cc new file mode 100644 index 0000000..6a5b3a4 --- /dev/null +++ b/ui/base/ui_base_switches.cc @@ -0,0 +1,13 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in the +// LICENSE file. + +#include "ui/base/ui_base_switches.h" + +namespace switches { + +// The language file that we want to try to open. Of the form +// language[-country] where language is the 2 letter code from ISO-639. +const char kLang[] = "lang"; + +} // namespace switches diff --git a/ui/base/ui_base_switches.h b/ui/base/ui_base_switches.h new file mode 100644 index 0000000..22fc9fe --- /dev/null +++ b/ui/base/ui_base_switches.h @@ -0,0 +1,17 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Defines all the command-line switches used by ui/base. + +#ifndef UI_BASE_UI_BASE_SWITCHES_H_ +#define UI_BASE_UI_BASE_SWITCHES_H_ +#pragma once + +namespace switches { + +extern const char kLang[]; + +} // namespace switches + +#endif // UI_BASE_UI_BASE_SWITCHES_H_ |