summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
Diffstat (limited to 'ui')
-rw-r--r--ui/DEPS1
-rw-r--r--ui/README.chromium16
-rw-r--r--ui/base/resource/data_pack.cc219
-rw-r--r--ui/base/resource/data_pack.h65
-rw-r--r--ui/base/resource/data_pack_unittest.cc76
-rw-r--r--ui/base/resource/resource_bundle.cc269
-rw-r--r--ui/base/resource/resource_bundle.h283
-rw-r--r--ui/base/resource/resource_bundle_dummy.cc67
-rw-r--r--ui/base/resource/resource_bundle_linux.cc148
-rw-r--r--ui/base/resource/resource_bundle_mac.mm72
-rw-r--r--ui/base/resource/resource_bundle_posix.cc121
-rw-r--r--ui/base/resource/resource_bundle_win.cc170
-rw-r--r--ui/base/test/data/data_pack_unittest/sample.pakbin0 -> 80 bytes
-rw-r--r--ui/base/test/data/resource.h28
-rw-r--r--ui/base/ui_base_paths.cc75
-rw-r--r--ui/base/ui_base_paths.h33
-rw-r--r--ui/base/ui_base_switches.cc13
-rw-r--r--ui/base/ui_base_switches.h17
18 files changed, 1673 insertions, 0 deletions
diff --git a/ui/DEPS b/ui/DEPS
index 3d8a962..bb1f5d9 100644
--- a/ui/DEPS
+++ b/ui/DEPS
@@ -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
new file mode 100644
index 0000000..fdbe2b5
--- /dev/null
+++ b/ui/base/test/data/data_pack_unittest/sample.pak
Binary files differ
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_