summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorerg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-11 22:09:55 +0000
committererg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-11 22:09:55 +0000
commit75cbb35fa7fb6ce0a511612ec91998c053247be8 (patch)
tree5abee27b2c5f2c60e5017aa6c00b43d9fe2376f4
parent9fa8c2f5e9581c2e521fd28aadedc4c77b9b2150 (diff)
downloadchromium_src-75cbb35fa7fb6ce0a511612ec91998c053247be8.zip
chromium_src-75cbb35fa7fb6ce0a511612ec91998c053247be8.tar.gz
chromium_src-75cbb35fa7fb6ce0a511612ec91998c053247be8.tar.bz2
Revert "Completely redo how themes are stored on disk and processed at install
time," as it fails valgrind tests. This reverts commit 86faccd1028937a69ccc718718fd48c06c0cd471 (r34379). Review URL: http://codereview.chromium.org/490025 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34385 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/base.gyp1
-rw-r--r--base/base.gypi1
-rw-r--r--base/data_pack.cc97
-rw-r--r--base/data_pack.h10
-rw-r--r--base/data_pack_unittest.cc54
-rw-r--r--chrome/browser/browser_theme_pack.cc864
-rw-r--r--chrome/browser/browser_theme_pack.h191
-rw-r--r--chrome/browser/browser_theme_pack_unittest.cc335
-rw-r--r--chrome/browser/browser_theme_provider.cc1105
-rw-r--r--chrome/browser/browser_theme_provider.h213
-rw-r--r--chrome/browser/browser_theme_provider_mac.mm11
-rw-r--r--chrome/browser/browser_theme_provider_unittest.cc179
-rw-r--r--chrome/browser/cocoa/download_shelf_controller.mm6
-rw-r--r--chrome/browser/extensions/theme_installed_infobar_delegate.cc4
-rw-r--r--chrome/browser/gtk/download_shelf_gtk.cc3
-rw-r--r--chrome/browser/gtk/gtk_theme_provider.cc225
-rw-r--r--chrome/browser/gtk/gtk_theme_provider.h44
-rw-r--r--chrome/browser/gtk/gtk_theme_provider_unittest.cc75
-rw-r--r--chrome/browser/profile.cc1
-rwxr-xr-xchrome/chrome_browser.gypi2
-rwxr-xr-xchrome/chrome_tests.gypi1
-rw-r--r--chrome/common/chrome_constants.cc2
-rw-r--r--chrome/common/chrome_constants.h2
-rw-r--r--chrome/common/pref_names.cc1
-rw-r--r--chrome/common/pref_names.h1
-rw-r--r--chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_inactivebin0 -> 48806 bytes
-rw-r--r--chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_incognitobin0 -> 50613 bytes
-rw-r--r--chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_incognito_inactivebin0 -> 57089 bytes
-rw-r--r--chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_originalbin0 -> 68244 bytes
-rw-r--r--chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_tab_background_incognitobin0 -> 30590 bytes
-rw-r--r--chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_tab_background_originalbin0 -> 28215 bytes
-rw-r--r--chrome/test/data/profiles/complex_theme/Default/Extensions/mblmlcbknbnfebdfjnolmcapmdofhmme/1.1/Cached Theme.pakbin1233037 -> 0 bytes
-rw-r--r--chrome/test/data/profiles/complex_theme/Default/PreferencesTemplate33
33 files changed, 1569 insertions, 1892 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 28cf048..e0a0fe9 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -185,6 +185,7 @@
'../third_party/icu/icu.gyp:icudata',
],
'sources!': [
+ 'data_pack_unittest.cc',
'file_descriptor_shuffle_unittest.cc',
],
}, { # OS != "win"
diff --git a/base/base.gypi b/base/base.gypi
index 77a919e..c19b343 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -331,6 +331,7 @@
'../chrome/third_party/wtl/include',
],
'sources!': [
+ 'data_pack.cc',
'event_recorder_stubs.cc',
'file_descriptor_shuffle.cc',
'message_pump_libevent.cc',
diff --git a/base/data_pack.cc b/base/data_pack.cc
index 1078d0a..27054d3 100644
--- a/base/data_pack.cc
+++ b/base/data_pack.cc
@@ -14,22 +14,17 @@
// 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;
+static const uint32_t kFileFormatVersion = 1;
// Length of file header: version and entry count.
-static const size_t kHeaderLength = 2 * sizeof(uint32);
+static const size_t kHeaderLength = 2 * sizeof(uint32_t);
-#pragma pack(push,1)
struct DataPackEntry {
- uint32 resource_id;
- uint32 file_offset;
- uint32 length;
+ uint32_t resource_id;
+ uint32_t file_offset;
+ uint32_t length;
static int CompareById(const void* void_key, const void* void_entry) {
- uint32 key = *reinterpret_cast<const uint32*>(void_key);
+ uint32_t key = *reinterpret_cast<const uint32_t*>(void_key);
const DataPackEntry* entry =
reinterpret_cast<const DataPackEntry*>(void_entry);
if (key < entry->resource_id) {
@@ -40,10 +35,7 @@ struct DataPackEntry {
return 0;
}
}
-};
-#pragma pack(pop)
-
-COMPILE_ASSERT(sizeof(DataPackEntry) == 12, size_of_header_must_be_twelve);
+} __attribute((packed));
} // anonymous namespace
@@ -58,13 +50,12 @@ DataPack::~DataPack() {
bool DataPack::Load(const FilePath& path) {
mmap_.reset(new file_util::MemoryMappedFile);
if (!mmap_->Initialize(path)) {
- DLOG(ERROR) << "Failed to mmap datapack";
- return false;
+ PCHECK(false) << "Failed to mmap " << path.value();
}
// Parse the header of the file.
- // First uint32: version; second: resource count.
- const uint32* ptr = reinterpret_cast<const uint32*>(mmap_->data());
+ // First uint32_t: version; second: resource count.
+ const uint32* ptr = reinterpret_cast<const uint32_t*>(mmap_->data());
uint32 version = ptr[0];
if (version != kFileFormatVersion) {
LOG(ERROR) << "Bad data pack version: got " << version << ", expected "
@@ -98,7 +89,7 @@ bool DataPack::Load(const FilePath& path) {
return true;
}
-bool DataPack::GetStringPiece(uint32 resource_id, StringPiece* data) {
+bool DataPack::GetStringPiece(uint32_t resource_id, StringPiece* data) {
// It won't be hard to make this endian-agnostic, but it's not worth
// bothering to do right now.
#if defined(__BYTE_ORDER)
@@ -114,6 +105,7 @@ bool DataPack::GetStringPiece(uint32 resource_id, StringPiece* data) {
bsearch(&resource_id, mmap_->data() + kHeaderLength, resource_count_,
sizeof(DataPackEntry), DataPackEntry::CompareById));
if (!target) {
+ LOG(ERROR) << "No resource found with id: " << resource_id;
return false;
}
@@ -121,7 +113,7 @@ bool DataPack::GetStringPiece(uint32 resource_id, StringPiece* data) {
return true;
}
-RefCountedStaticMemory* DataPack::GetStaticMemory(uint32 resource_id) {
+RefCountedStaticMemory* DataPack::GetStaticMemory(uint32_t resource_id) {
base::StringPiece piece;
if (!GetStringPiece(resource_id, &piece))
return NULL;
@@ -130,67 +122,4 @@ RefCountedStaticMemory* DataPack::GetStaticMemory(uint32 resource_id) {
reinterpret_cast<const unsigned char*>(piece.data()), piece.length());
}
-// static
-bool DataPack::WritePack(const FilePath& path,
- const std::map<uint32, 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, 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, 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 base
diff --git a/base/data_pack.h b/base/data_pack.h
index 8938491..7c9abde 100644
--- a/base/data_pack.h
+++ b/base/data_pack.h
@@ -9,8 +9,6 @@
#ifndef BASE_DATA_PACK_H_
#define BASE_DATA_PACK_H_
-#include <map>
-
#include "base/basictypes.h"
#include "base/ref_counted_memory.h"
#include "base/scoped_ptr.h"
@@ -35,16 +33,12 @@ class DataPack {
// 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, StringPiece* data);
+ bool GetStringPiece(uint32_t resource_id, StringPiece* data);
// 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);
-
- // Writes a pack file containing |resources| to |path|.
- static bool WritePack(const FilePath& path,
- const std::map<uint32, StringPiece>& resources);
+ RefCountedStaticMemory* GetStaticMemory(uint32_t resource_id);
private:
// The memory-mapped data.
diff --git a/base/data_pack_unittest.cc b/base/data_pack_unittest.cc
index d089b28..a62acf0 100644
--- a/base/data_pack_unittest.cc
+++ b/base/data_pack_unittest.cc
@@ -5,20 +5,24 @@
#include "base/data_pack.h"
#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"
-TEST(DataPackTest, Load) {
- FilePath data_path;
- PathService::Get(base::DIR_SOURCE_ROOT, &data_path);
- data_path = data_path.Append(
+class DataPackTest : public testing::Test {
+ public:
+ DataPackTest() {
+ PathService::Get(base::DIR_SOURCE_ROOT, &data_path_);
+ data_path_ = data_path_.Append(
FILE_PATH_LITERAL("base/data/data_pack_unittest/sample.pak"));
+ }
+ FilePath data_path_;
+};
+
+TEST_F(DataPackTest, Load) {
base::DataPack pack;
- ASSERT_TRUE(pack.Load(data_path));
+ ASSERT_TRUE(pack.Load(data_path_));
base::StringPiece data;
ASSERT_TRUE(pack.GetStringPiece(4, &data));
@@ -35,39 +39,3 @@ TEST(DataPackTest, Load) {
// 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(base::DataPack::WritePack(file, resources));
-
- // Now try to read the data back in.
- base::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);
-}
diff --git a/chrome/browser/browser_theme_pack.cc b/chrome/browser/browser_theme_pack.cc
deleted file mode 100644
index f30bd6b..0000000
--- a/chrome/browser/browser_theme_pack.cc
+++ /dev/null
@@ -1,864 +0,0 @@
-// 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.
-
-#include "chrome/browser/browser_theme_pack.h"
-
-#include <climits>
-
-#include "app/gfx/codec/png_codec.h"
-#include "app/gfx/skbitmap_operations.h"
-#include "base/data_pack.h"
-#include "base/logging.h"
-#include "base/stl_util-inl.h"
-#include "base/string_util.h"
-#include "base/values.h"
-#include "chrome/browser/browser_theme_provider.h"
-#include "chrome/browser/chrome_thread.h"
-#include "chrome/browser/theme_resources_util.h"
-#include "chrome/common/extensions/extension.h"
-#include "grit/app_resources.h"
-#include "grit/theme_resources.h"
-#include "net/base/file_stream.h"
-#include "net/base/net_errors.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkUnPreMultiply.h"
-
-namespace {
-
-// Version number of the current theme pack. We just throw out and rebuild
-// theme packs that aren't int-equal to this.
-const int kThemePackVersion = 1;
-
-// IDs that are in the DataPack won't clash with the positive integer
-// int32_t. kHeaderID should always have the maximum value because we want the
-// "header" to be written last. That way we can detect whether the pack was
-// successfully written and ignore and regenerate if it was only partially
-// written (i.e. chrome crashed on a different thread while writing the pack).
-const int kHeaderID = UINT_MAX - 1;
-const int kTintsID = UINT_MAX - 2;
-const int kColorsID = UINT_MAX - 3;
-const int kDisplayPropertiesID = UINT_MAX - 4;
-
-// Static size of the tint/color/display property arrays that are mmapped.
-const int kTintArraySize = 6;
-const int kColorArraySize = 19;
-const int kDisplayPropertySize = 3;
-
-// The sum of kFrameBorderThickness and kNonClientRestoredExtraThickness from
-// OpaqueBrowserFrameView.
-const int kRestoredTabVerticalOffset = 15;
-
-
-struct StringToIntTable {
- const char* key;
- int id;
-};
-
-// Strings used by themes to identify tints in the JSON.
-StringToIntTable kTintTable[] = {
- { "buttons", BrowserThemeProvider::TINT_BUTTONS },
- { "frame", BrowserThemeProvider::TINT_FRAME },
- { "frame_inactive", BrowserThemeProvider::TINT_FRAME_INACTIVE },
- { "frame_incognito_inactive",
- BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE },
- { "background_tab", BrowserThemeProvider::TINT_BACKGROUND_TAB },
- { NULL, 0 }
-};
-
-// Strings used by themes to identify colors in the JSON.
-StringToIntTable kColorTable[] = {
- { "frame", BrowserThemeProvider::COLOR_FRAME },
- { "frame_inactive", BrowserThemeProvider::COLOR_FRAME_INACTIVE },
- { "frame_incognito", BrowserThemeProvider::COLOR_FRAME_INCOGNITO },
- { "frame_incognito_inactive",
- BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE },
- { "toolbar", BrowserThemeProvider::COLOR_TOOLBAR },
- { "tab_text", BrowserThemeProvider::COLOR_TAB_TEXT },
- { "tab_background_text", BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT },
- { "bookmark_text", BrowserThemeProvider::COLOR_BOOKMARK_TEXT },
- { "ntp_background", BrowserThemeProvider::COLOR_NTP_BACKGROUND },
- { "ntp_text", BrowserThemeProvider::COLOR_NTP_TEXT },
- { "ntp_link", BrowserThemeProvider::COLOR_NTP_LINK },
- { "ntp_link_underline", BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE },
- { "ntp_header", BrowserThemeProvider::COLOR_NTP_HEADER },
- { "ntp_section", BrowserThemeProvider::COLOR_NTP_SECTION },
- { "ntp_section_text", BrowserThemeProvider::COLOR_NTP_SECTION_TEXT },
- { "ntp_section_link", BrowserThemeProvider::COLOR_NTP_SECTION_LINK },
- { "ntp_section_link_underline",
- BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE },
- { "control_background", BrowserThemeProvider::COLOR_CONTROL_BACKGROUND },
- { "button_background", BrowserThemeProvider::COLOR_BUTTON_BACKGROUND },
- { NULL, 0 }
-};
-
-// Strings used by themes to identify display properties keys in JSON.
-StringToIntTable kDisplayProperties[] = {
- { "ntp_background_alignment",
- BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT },
- { "ntp_background_repeat", BrowserThemeProvider::NTP_BACKGROUND_TILING },
- { "ntp_logo_alternate", BrowserThemeProvider::NTP_LOGO_ALTERNATE },
- { NULL, 0 }
-};
-
-// Strings used by the tiling values in JSON.
-StringToIntTable kTilingStrings[] = {
- { "no-repeat", BrowserThemeProvider::NO_REPEAT },
- { "repeat-x", BrowserThemeProvider::REPEAT_X },
- { "repeat-y", BrowserThemeProvider::REPEAT_Y },
- { "repeat", BrowserThemeProvider::REPEAT },
- { NULL, 0 }
-};
-
-int GetIntForString(const std::string& key, StringToIntTable* table) {
- for (int i = 0; table[i].key != NULL; ++i) {
- if (base::strcasecmp(key.c_str(), table[i].key) == 0) {
- return table[i].id;
- }
- }
-
- return -1;
-}
-
-struct IntToIntTable {
- int key;
- int value;
-};
-
-// Mapping used in GenerateFrameImages() to associate frame images with the
-// tint ID that should maybe be applied to it.
-IntToIntTable kFrameTintMap[] = {
- { IDR_THEME_FRAME, BrowserThemeProvider::TINT_FRAME },
- { IDR_THEME_FRAME_INACTIVE, BrowserThemeProvider::TINT_FRAME_INACTIVE },
- { IDR_THEME_FRAME_OVERLAY, BrowserThemeProvider::TINT_FRAME },
- { IDR_THEME_FRAME_OVERLAY_INACTIVE,
- BrowserThemeProvider::TINT_FRAME_INACTIVE },
- { IDR_THEME_FRAME_INCOGNITO, BrowserThemeProvider::TINT_FRAME_INCOGNITO },
- { IDR_THEME_FRAME_INCOGNITO_INACTIVE,
- BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE }
-};
-
-// Mapping used in GenerateTabBackgroundImages() to associate what frame image
-// goes with which tab background.
-IntToIntTable kTabBackgroundMap[] = {
- { IDR_THEME_TAB_BACKGROUND, IDR_THEME_FRAME },
- { IDR_THEME_TAB_BACKGROUND_INCOGNITO, IDR_THEME_FRAME_INCOGNITO }
-};
-
-// A list of images that don't need tinting or any other modification and can
-// be byte-copied directly into the finished DataPack. This should contain all
-// themeable image IDs that aren't in kFrameTintMap or kTabBackgroundMap.
-const int kPreloadIDs[] = {
- IDR_THEME_TOOLBAR,
- IDR_THEME_NTP_BACKGROUND,
- IDR_THEME_BUTTON_BACKGROUND,
- IDR_THEME_NTP_ATTRIBUTION,
- IDR_THEME_WINDOW_CONTROL_BACKGROUND
-};
-
-// The image resources that will be tinted by the 'button' tint value.
-const int kToolbarButtonIDs[] = {
- IDR_BACK, IDR_BACK_D, IDR_BACK_H, IDR_BACK_P,
- IDR_FORWARD, IDR_FORWARD_D, IDR_FORWARD_H, IDR_FORWARD_P,
- IDR_RELOAD, IDR_RELOAD_H, IDR_RELOAD_P,
- IDR_HOME, IDR_HOME_H, IDR_HOME_P,
- IDR_STAR, IDR_STAR_NOBORDER, IDR_STAR_NOBORDER_CENTER, IDR_STAR_D, IDR_STAR_H,
- IDR_STAR_P,
- IDR_STARRED, IDR_STARRED_NOBORDER, IDR_STARRED_NOBORDER_CENTER, IDR_STARRED_H,
- IDR_STARRED_P,
- IDR_GO, IDR_GO_NOBORDER, IDR_GO_NOBORDER_CENTER, IDR_GO_H, IDR_GO_P,
- IDR_STOP, IDR_STOP_NOBORDER, IDR_STOP_NOBORDER_CENTER, IDR_STOP_H, IDR_STOP_P,
- IDR_MENU_BOOKMARK,
- IDR_MENU_PAGE, IDR_MENU_PAGE_RTL,
- IDR_MENU_CHROME, IDR_MENU_CHROME_RTL,
- IDR_MENU_DROPARROW,
- IDR_THROBBER, IDR_THROBBER_WAITING, IDR_THROBBER_LIGHT,
- IDR_LOCATIONBG
-};
-
-// Returns a piece of memory with the contents of the file |path|.
-RefCountedMemory* ReadFileData(const FilePath& path) {
- if (!path.empty()) {
- net::FileStream file;
- int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
- if (file.Open(path, flags) == net::OK) {
- int64 avail = file.Available();
- if (avail > 0 && avail < INT_MAX) {
- size_t size = static_cast<size_t>(avail);
- std::vector<unsigned char> raw_data;
- raw_data.resize(size);
- char* data = reinterpret_cast<char*>(&(raw_data.front()));
- if (file.ReadUntilComplete(data, size) == avail)
- return RefCountedBytes::TakeVector(&raw_data);
- }
- }
- }
-
- return NULL;
-}
-
-// Does error checking for invalid incoming data while trying to read an
-// floaing point value.
-bool ValidRealValue(ListValue* tint_list, int index, double* out) {
- if (tint_list->GetReal(index, out))
- return true;
-
- int value = 0;
- if (tint_list->GetInteger(index, &value)) {
- *out = value;
- return true;
- }
-
- return false;
-}
-
-} // namespace
-
-BrowserThemePack::~BrowserThemePack() {
- if (!data_pack_.get()) {
- delete header_;
- delete [] tints_;
- delete [] colors_;
- delete [] display_properties_;
- }
-
- STLDeleteValues(&image_cache_);
-}
-
-// static
-BrowserThemePack* BrowserThemePack::BuildFromExtension(Extension* extension) {
- DCHECK(extension);
- DCHECK(extension->IsTheme());
-
- BrowserThemePack* pack = new BrowserThemePack;
- pack->BuildHeader(extension);
- pack->BuildTintsFromJSON(extension->GetThemeTints());
- pack->BuildColorsFromJSON(extension->GetThemeColors());
- pack->BuildDisplayPropertiesFromJSON(extension->GetThemeDisplayProperties());
-
- // Builds the images. (Image building is dependent on tints).
- std::map<int, FilePath> file_paths;
- pack->ParseImageNamesFromJSON(extension->GetThemeImages(),
- extension->path(),
- &file_paths);
-
- pack->LoadRawBitmapsTo(file_paths, &pack->image_cache_);
-
- pack->GenerateFrameImages(&pack->image_cache_);
-
-#if !defined(OS_MACOSX)
- // OSX uses its own special buttons that are PDFs that do odd sorts of vector
- // graphics tricks. Other platforms use bitmaps and we must pre-tint them.
- pack->GenerateTintedButtons(
- pack->GetTintInternal(BrowserThemeProvider::TINT_BUTTONS),
- &pack->image_cache_);
-#endif
-
- pack->GenerateTabBackgroundImages(&pack->image_cache_);
-
- // Repack all the images from |image_cache_| into |image_memory_| for
- // writing to the data pack
- pack->RepackImageCacheToImageMemory();
-
- // The BrowserThemePack is now in a consistent state.
- return pack;
-}
-
-// static
-scoped_refptr<BrowserThemePack> BrowserThemePack::BuildFromDataPack(
- FilePath path, const std::string& expected_id) {
- scoped_refptr<BrowserThemePack> pack = new BrowserThemePack;
- pack->data_pack_.reset(new base::DataPack);
-
- if (!pack->data_pack_->Load(path)) {
- LOG(ERROR) << "Failed to load theme data pack.";
- return NULL;
- }
-
- base::StringPiece pointer;
- if (!pack->data_pack_->GetStringPiece(kHeaderID, &pointer))
- return NULL;
- pack->header_ = reinterpret_cast<BrowserThemePackHeader*>(const_cast<char*>(
- pointer.data()));
-
- if (pack->header_->version != kThemePackVersion)
- return NULL;
- // TODO(erg): Check endianess once DataPack works on the other endian.
- std::string theme_id(reinterpret_cast<char*>(pack->header_->theme_id),
- Extension::kIdSize);
- std::string truncated_id = expected_id.substr(0, Extension::kIdSize);
- if (theme_id != truncated_id) {
- DLOG(ERROR) << "Wrong id: " << theme_id << " vs " << expected_id;
- return NULL;
- }
-
- if (!pack->data_pack_->GetStringPiece(kTintsID, &pointer))
- return NULL;
- pack->tints_ = reinterpret_cast<TintEntry*>(const_cast<char*>(
- pointer.data()));
-
- if (!pack->data_pack_->GetStringPiece(kColorsID, &pointer))
- return NULL;
- pack->colors_ =
- reinterpret_cast<ColorPair*>(const_cast<char*>(pointer.data()));
-
- if (!pack->data_pack_->GetStringPiece(kDisplayPropertiesID, &pointer))
- return NULL;
- pack->display_properties_ = reinterpret_cast<DisplayPropertyPair*>(
- const_cast<char*>(pointer.data()));
-
- return pack;
-}
-
-bool BrowserThemePack::WriteToDisk(FilePath path) const {
- std::map<uint32, base::StringPiece> resources;
-
- resources[kHeaderID] = base::StringPiece(
- reinterpret_cast<const char*>(header_), sizeof(BrowserThemePackHeader));
- resources[kTintsID] = base::StringPiece(
- reinterpret_cast<const char*>(tints_), sizeof(TintEntry[kTintArraySize]));
- resources[kColorsID] = base::StringPiece(
- reinterpret_cast<const char*>(colors_),
- sizeof(ColorPair[kColorArraySize]));
- resources[kDisplayPropertiesID] = base::StringPiece(
- reinterpret_cast<const char*>(display_properties_),
- sizeof(DisplayPropertyPair[kDisplayPropertySize]));
-
- for (RawImages::const_iterator it = image_memory_.begin();
- it != image_memory_.end(); ++it) {
- resources[it->first] = base::StringPiece(
- reinterpret_cast<const char*>(it->second->front()), it->second->size());
- }
-
- return base::DataPack::WritePack(path, resources);
-}
-
-bool BrowserThemePack::GetTint(int id, color_utils::HSL* hsl) const {
- if (tints_) {
- for (int i = 0; i < kTintArraySize; ++i) {
- if (tints_[i].id == id) {
- hsl->h = tints_[i].h;
- hsl->s = tints_[i].s;
- hsl->l = tints_[i].l;
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool BrowserThemePack::GetColor(int id, SkColor* color) const {
- if (colors_) {
- for (int i = 0; i < kColorArraySize; ++i) {
- if (colors_[i].id == id) {
- *color = colors_[i].color;
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool BrowserThemePack::GetDisplayProperty(int id, int* result) const {
- if (display_properties_) {
- for (int i = 0; i < kDisplayPropertySize; ++i) {
- if (display_properties_[i].id == id) {
- *result = display_properties_[i].property;
- return true;
- }
- }
- }
-
- return false;
-}
-
-SkBitmap* BrowserThemePack::GetBitmapNamed(int id) const {
- // Check our cache of prepared images, first.
- ImageCache::const_iterator image_iter = image_cache_.find(id);
- if (image_iter != image_cache_.end())
- return image_iter->second;
-
- scoped_refptr<RefCountedMemory> memory;
- if (data_pack_.get()) {
- memory = data_pack_->GetStaticMemory(id);
- } else {
- RawImages::const_iterator it = image_memory_.find(id);
- if (it != image_memory_.end()) {
- memory = it->second;
- }
- }
-
- if (memory.get()) {
- // Decode the PNG.
- SkBitmap bitmap;
- if (!gfx::PNGCodec::Decode(memory->front(), memory->size(),
- &bitmap)) {
- NOTREACHED() << "Unable to decode theme image resource " << id
- << " from saved DataPack.";
- return NULL;
- }
-
- SkBitmap* ret = new SkBitmap(bitmap);
- image_cache_[id] = ret;
-
- return ret;
- }
-
- return NULL;
-}
-
-RefCountedMemory* BrowserThemePack::GetRawData(int id) const {
- RefCountedMemory* memory = NULL;
-
- if (data_pack_.get()) {
- memory = data_pack_->GetStaticMemory(id);
- } else {
- RawImages::const_iterator it = image_memory_.find(id);
- if (it != image_memory_.end()) {
- memory = it->second;
- }
- }
-
- return memory;
-}
-
-bool BrowserThemePack::HasCustomImage(int id) const {
- if (data_pack_.get()) {
- base::StringPiece ignored;
- return data_pack_->GetStringPiece(id, &ignored);
- } else {
- return image_memory_.count(id) > 0;
- }
-}
-
-// private:
-
-BrowserThemePack::BrowserThemePack()
- : header_(NULL),
- tints_(NULL),
- colors_(NULL),
- display_properties_(NULL) {
-}
-
-void BrowserThemePack::BuildHeader(Extension* extension) {
- header_ = new BrowserThemePackHeader;
- header_->version = kThemePackVersion;
-
- // TODO(erg): Need to make this endian safe on other computers. Prerequisite
- // is that base::DataPack removes this same check.
-#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
- header_->little_endian = 1;
-
- const std::string& id = extension->id();
- memcpy(header_->theme_id, id.c_str(), Extension::kIdSize);
-}
-
-void BrowserThemePack::BuildTintsFromJSON(DictionaryValue* tints_value) {
- tints_ = new TintEntry[kTintArraySize];
- for (int i = 0; i < kTintArraySize; ++i) {
- tints_[i].id = -1;
- tints_[i].h = -1;
- tints_[i].s = -1;
- tints_[i].l = -1;
- }
-
- // Parse the incoming data from |tints_value| into an intermediary structure.
- std::map<int, color_utils::HSL> temp_tints;
- for (DictionaryValue::key_iterator iter(tints_value->begin_keys());
- iter != tints_value->end_keys(); ++iter) {
- ListValue* tint_list;
- if (tints_value->GetList(*iter, &tint_list) &&
- (tint_list->GetSize() == 3)) {
- color_utils::HSL hsl = { -1, -1, -1 };
-
- if (ValidRealValue(tint_list, 0, &hsl.h) &&
- ValidRealValue(tint_list, 1, &hsl.s) &&
- ValidRealValue(tint_list, 2, &hsl.l)) {
-
- int id = GetIntForString(WideToUTF8(*iter), kTintTable);
- if (id != -1) {
- temp_tints[id] = hsl;
- }
- }
- }
- }
-
- // Copy data from the intermediary data structure to the array.
- int count = 0;
- for (std::map<int, color_utils::HSL>::const_iterator it =
- temp_tints.begin(); it != temp_tints.end() && count < kTintArraySize;
- ++it, ++count) {
- tints_[count].id = it->first;
- tints_[count].h = it->second.h;
- tints_[count].s = it->second.s;
- tints_[count].l = it->second.l;
- }
-}
-
-void BrowserThemePack::BuildColorsFromJSON(DictionaryValue* colors_value) {
- colors_ = new ColorPair[kColorArraySize];
- for (int i = 0; i < kColorArraySize; ++i) {
- colors_[i].id = -1;
- colors_[i].color = SkColorSetRGB(0, 0, 0);
- }
-
- std::map<int, SkColor> temp_colors;
- ReadColorsFromJSON(colors_value, &temp_colors);
- GenerateMissingColors(&temp_colors);
-
- // Copy data from the intermediary data structure to the array.
- int count = 0;
- for (std::map<int, SkColor>::const_iterator it = temp_colors.begin();
- it != temp_colors.end() && count < kColorArraySize; ++it, ++count) {
- colors_[count].id = it->first;
- colors_[count].color = it->second;
- }
-}
-
-void BrowserThemePack::ReadColorsFromJSON(
- DictionaryValue* colors_value,
- std::map<int, SkColor>* temp_colors) {
- // Parse the incoming data from |colors_value| into an intermediary structure.
- for (DictionaryValue::key_iterator iter(colors_value->begin_keys());
- iter != colors_value->end_keys(); ++iter) {
- ListValue* color_list;
- if (colors_value->GetList(*iter, &color_list) &&
- ((color_list->GetSize() == 3) || (color_list->GetSize() == 4))) {
- SkColor color = SK_ColorWHITE;
- int r, g, b;
- if (color_list->GetInteger(0, &r) &&
- color_list->GetInteger(1, &g) &&
- color_list->GetInteger(2, &b)) {
- if (color_list->GetSize() == 4) {
- double alpha;
- int alpha_int;
- if (color_list->GetReal(3, &alpha)) {
- color = SkColorSetARGB(static_cast<int>(alpha * 255), r, g, b);
- } else if (color_list->GetInteger(3, &alpha_int) &&
- (alpha_int == 0 || alpha_int == 1)) {
- color = SkColorSetARGB(alpha_int ? 255 : 0, r, g, b);
- } else {
- // Invalid entry for part 4.
- continue;
- }
- } else {
- color = SkColorSetRGB(r, g, b);
- }
-
- int id = GetIntForString(WideToUTF8(*iter), kColorTable);
- if (id != -1) {
- (*temp_colors)[id] = color;
- }
- }
- }
- }
-}
-
-void BrowserThemePack::GenerateMissingColors(
- std::map<int, SkColor>* colors) {
- // Generate link colors, if missing. (See GetColor()).
- if (!colors->count(BrowserThemeProvider::COLOR_NTP_HEADER) &&
- colors->count(BrowserThemeProvider::COLOR_NTP_SECTION)) {
- (*colors)[BrowserThemeProvider::COLOR_NTP_HEADER] =
- (*colors)[BrowserThemeProvider::COLOR_NTP_SECTION];
- }
-
- if (!colors->count(BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE) &&
- colors->count(BrowserThemeProvider::COLOR_NTP_SECTION_LINK)) {
- SkColor color_section_link =
- (*colors)[BrowserThemeProvider::COLOR_NTP_SECTION_LINK];
- (*colors)[BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE] =
- SkColorSetA(color_section_link, SkColorGetA(color_section_link) / 3);
- }
-
- if (!colors->count(BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE) &&
- colors->count(BrowserThemeProvider::COLOR_NTP_LINK)) {
- SkColor color_link = (*colors)[BrowserThemeProvider::COLOR_NTP_LINK];
- (*colors)[BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE] =
- SkColorSetA(color_link, SkColorGetA(color_link) / 3);
- }
-
- // Generate frame colors, if missing. (See GenerateFrameColors()).
- SkColor frame;
- std::map<int, SkColor>::const_iterator it =
- colors->find(BrowserThemeProvider::COLOR_FRAME);
- if (it != colors->end()) {
- frame = it->second;
- } else {
- frame = BrowserThemeProvider::GetDefaultColor(
- BrowserThemeProvider::COLOR_FRAME);
- }
-
- if (!colors->count(BrowserThemeProvider::COLOR_FRAME)) {
- (*colors)[BrowserThemeProvider::COLOR_FRAME] =
- HSLShift(frame, GetTintInternal(BrowserThemeProvider::TINT_FRAME));
- }
- if (!colors->count(BrowserThemeProvider::COLOR_FRAME_INACTIVE)) {
- (*colors)[BrowserThemeProvider::COLOR_FRAME_INACTIVE] =
- HSLShift(frame, GetTintInternal(
- BrowserThemeProvider::TINT_FRAME_INACTIVE));
- }
- if (!colors->count(BrowserThemeProvider::COLOR_FRAME_INCOGNITO)) {
- (*colors)[BrowserThemeProvider::COLOR_FRAME_INCOGNITO] =
- HSLShift(frame, GetTintInternal(
- BrowserThemeProvider::TINT_FRAME_INCOGNITO));
- }
- if (!colors->count(BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE)) {
- (*colors)[BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE] =
- HSLShift(frame, GetTintInternal(
- BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE));
- }
-}
-
-void BrowserThemePack::BuildDisplayPropertiesFromJSON(
- DictionaryValue* display_properties_value) {
- display_properties_ = new DisplayPropertyPair[kDisplayPropertySize];
- for (int i = 0; i < kDisplayPropertySize; ++i) {
- display_properties_[i].id = -1;
- display_properties_[i].property = 0;
- }
-
- std::map<int, int> temp_properties;
- for (DictionaryValue::key_iterator iter(
- display_properties_value->begin_keys());
- iter != display_properties_value->end_keys(); ++iter) {
- int property_id = GetIntForString(WideToUTF8(*iter), kDisplayProperties);
- switch (property_id) {
- case BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT: {
- std::string val;
- if (display_properties_value->GetString(*iter, &val)) {
- temp_properties[BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT] =
- BrowserThemeProvider::StringToAlignment(val);
- }
- break;
- }
- case BrowserThemeProvider::NTP_BACKGROUND_TILING: {
- std::string val;
- if (display_properties_value->GetString(*iter, &val)) {
- temp_properties[BrowserThemeProvider::NTP_BACKGROUND_TILING] =
- GetIntForString(val, kTilingStrings);
- }
- break;
- }
- case BrowserThemeProvider::NTP_LOGO_ALTERNATE: {
- int val = 0;
- if (display_properties_value->GetInteger(*iter, &val))
- temp_properties[BrowserThemeProvider::NTP_LOGO_ALTERNATE] = val;
- break;
- }
- }
- }
-
- // Copy data from the intermediary data structure to the array.
- int count = 0;
- for (std::map<int, int>::const_iterator it = temp_properties.begin();
- it != temp_properties.end() && count < kDisplayPropertySize;
- ++it, ++count) {
- display_properties_[count].id = it->first;
- display_properties_[count].property = it->second;
- }
-}
-
-void BrowserThemePack::ParseImageNamesFromJSON(
- DictionaryValue* images_value,
- FilePath images_path,
- std::map<int, FilePath>* file_paths) const {
- for (DictionaryValue::key_iterator iter(images_value->begin_keys());
- iter != images_value->end_keys(); ++iter) {
- std::string val;
- if (images_value->GetString(*iter, &val)) {
- int id = ThemeResourcesUtil::GetId(WideToUTF8(*iter));
- if (id != -1)
- (*file_paths)[id] = images_path.AppendASCII(val);
- }
- }
-}
-
-void BrowserThemePack::LoadRawBitmapsTo(
- const std::map<int, FilePath>& file_paths,
- ImageCache* raw_bitmaps) {
- for (std::map<int, FilePath>::const_iterator it = file_paths.begin();
- it != file_paths.end(); ++it) {
- scoped_refptr<RefCountedMemory> raw_data(ReadFileData(it->second));
- int id = it->first;
-
- // Some images need to go directly into |image_memory_|. No modification is
- // necessary or desirable.
- bool is_copyable = false;
- for (size_t i = 0; i < arraysize(kPreloadIDs); ++i) {
- if (kPreloadIDs[i] == id) {
- is_copyable = true;
- break;
- }
- }
-
- if (is_copyable) {
- image_memory_[id] = raw_data;
- } else if (raw_data.get() && raw_data->size()) {
- // Decode the PNG.
- SkBitmap bitmap;
- if (gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(),
- &bitmap)) {
- (*raw_bitmaps)[it->first] = new SkBitmap(bitmap);
- } else {
- NOTREACHED() << "Unable to decode theme image resource " << it->first;
- }
- }
- }
-}
-
-void BrowserThemePack::GenerateFrameImages(ImageCache* bitmaps) const {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-
- // Create all the output bitmaps in a separate cache and move them back into
- // the input bitmaps because there can be name collisions.
- ImageCache temp_output;
-
- for (size_t i = 0; i < arraysize(kFrameTintMap); ++i) {
- int id = kFrameTintMap[i].key;
- scoped_ptr<SkBitmap> frame;
- // If there's no frame image provided for the specified id, then load
- // the default provided frame. If that's not provided, skip this whole
- // thing and just use the default images.
- int base_id;
-
- if (id == IDR_THEME_FRAME_INCOGNITO_INACTIVE) {
- base_id = bitmaps->count(IDR_THEME_FRAME_INCOGNITO) ?
- IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME;
- } else if (id == IDR_THEME_FRAME_OVERLAY_INACTIVE) {
- base_id = IDR_THEME_FRAME_OVERLAY;
- } else if (id == IDR_THEME_FRAME_INACTIVE) {
- base_id = IDR_THEME_FRAME;
- } else if (id == IDR_THEME_FRAME_INCOGNITO &&
- !bitmaps->count(IDR_THEME_FRAME_INCOGNITO)) {
- base_id = IDR_THEME_FRAME;
- } else {
- base_id = id;
- }
-
- if (bitmaps->count(id)) {
- frame.reset(new SkBitmap(*(*bitmaps)[id]));
- } else if (base_id != id && bitmaps->count(base_id)) {
- frame.reset(new SkBitmap(*(*bitmaps)[base_id]));
- } else if (base_id == IDR_THEME_FRAME_OVERLAY &&
- bitmaps->count(IDR_THEME_FRAME)) {
- // If there is no theme overlay, don't tint the default frame,
- // because it will overwrite the custom frame image when we cache and
- // reload from disk.
- frame.reset(NULL);
- } else {
- // If the theme doesn't specify an image, then apply the tint to
- // the default frame.
- frame.reset(new SkBitmap(*rb.GetBitmapNamed(IDR_THEME_FRAME)));
- }
-
- if (frame.get()) {
- temp_output[id] = new SkBitmap(
- SkBitmapOperations::CreateHSLShiftedBitmap(
- *frame, GetTintInternal(kFrameTintMap[i].value)));
- }
- }
-
- MergeImageCaches(temp_output, bitmaps);
-}
-
-void BrowserThemePack::GenerateTintedButtons(
- color_utils::HSL button_tint,
- ImageCache* processed_bitmaps) const {
- if (button_tint.h != -1 || button_tint.s != -1 || button_tint.l != -1) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- for (size_t i = 0; i < arraysize(kToolbarButtonIDs); ++i) {
- scoped_ptr<SkBitmap> button(
- new SkBitmap(*rb.GetBitmapNamed(kToolbarButtonIDs[i])));
- (*processed_bitmaps)[kToolbarButtonIDs[i]] = new SkBitmap(
- SkBitmapOperations::CreateHSLShiftedBitmap(*button, button_tint));
- }
- }
-}
-
-void BrowserThemePack::GenerateTabBackgroundImages(ImageCache* bitmaps) const {
- ImageCache temp_output;
- for (size_t i = 0; i < arraysize(kTabBackgroundMap); ++i) {
- int id = kTabBackgroundMap[i].key;
- int base_id = kTabBackgroundMap[i].value;
-
- // We only need to generate the background tab images if we were provided
- // with a IDR_THEME_FRAME.
- ImageCache::const_iterator it = bitmaps->find(base_id);
- if (it != bitmaps->end()) {
- SkBitmap bg_tint = SkBitmapOperations::CreateHSLShiftedBitmap(
- *(it->second), GetTintInternal(
- BrowserThemeProvider::TINT_BACKGROUND_TAB));
- int vertical_offset = bitmaps->count(id) ? kRestoredTabVerticalOffset : 0;
- SkBitmap* bg_tab = new SkBitmap(SkBitmapOperations::CreateTiledBitmap(
- bg_tint, 0, vertical_offset, bg_tint.width(), bg_tint.height()));
-
- // If they've provided a custom image, overlay it.
- ImageCache::const_iterator overlay_it = bitmaps->find(id);
- if (overlay_it != bitmaps->end()) {
- SkBitmap* overlay = overlay_it->second;
- SkCanvas canvas(*bg_tab);
- for (int x = 0; x < bg_tab->width(); x += overlay->width())
- canvas.drawBitmap(*overlay, static_cast<SkScalar>(x), 0, NULL);
- }
-
- temp_output[id] = bg_tab;
- }
- }
-
- MergeImageCaches(temp_output, bitmaps);
-}
-
-void BrowserThemePack::RepackImageCacheToImageMemory() {
- // TODO(erg): This shouldn't be done on the main thread. This should be done
- // during the WriteToDisk() method, but will require some tricky locking.
- for (ImageCache::const_iterator it = image_cache_.begin();
- it != image_cache_.end(); ++it) {
- std::vector<unsigned char> image_data;
- if (!gfx::PNGCodec::EncodeBGRASkBitmap(*(it->second), false, &image_data)) {
- NOTREACHED() << "Image file for resource " << it->first
- << " could not be encoded.";
- } else {
- image_memory_[it->first] = RefCountedBytes::TakeVector(&image_data);
- }
- }
-}
-
-void BrowserThemePack::MergeImageCaches(
- const ImageCache& source, ImageCache* destination) const {
-
- for (ImageCache::const_iterator it = source.begin(); it != source.end();
- ++it) {
- ImageCache::const_iterator bitmap_it = destination->find(it->first);
- if (bitmap_it != destination->end())
- delete bitmap_it->second;
-
- (*destination)[it->first] = it->second;
- }
-}
-
-color_utils::HSL BrowserThemePack::GetTintInternal(int id) const {
- if (tints_) {
- for (int i = 0; i < kTintArraySize; ++i) {
- if (tints_[i].id == id) {
- color_utils::HSL hsl;
- hsl.h = tints_[i].h;
- hsl.s = tints_[i].s;
- hsl.l = tints_[i].l;
- return hsl;
- }
- }
- }
-
- return BrowserThemeProvider::GetDefaultTint(id);
-}
diff --git a/chrome/browser/browser_theme_pack.h b/chrome/browser/browser_theme_pack.h
deleted file mode 100644
index 4287617..0000000
--- a/chrome/browser/browser_theme_pack.h
+++ /dev/null
@@ -1,191 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_BROWSER_THEME_PACK_H_
-#define CHROME_BROWSER_BROWSER_THEME_PACK_H_
-
-#include <map>
-#include <string>
-
-#include "app/gfx/color_utils.h"
-#include "base/basictypes.h"
-#include "base/scoped_ptr.h"
-#include "base/ref_counted.h"
-#include "chrome/common/extensions/extension.h"
-
-class BrowserThemeProviderTest;
-namespace base {
-class DataPack;
-}
-class DictionaryValue;
-class FilePath;
-class RefCountedMemory;
-
-// An optimized representation of a theme, backed by a mmapped DataPack.
-//
-// The idea is to pre-process all images (tinting, compositing, etc) at theme
-// install time, save all the PNG-ified data into an mmappable file so we don't
-// suffer multiple file system access times, therefore solving two of the
-// problems with the previous implementation.
-//
-// A note on const-ness. All public, non-static methods are const. We do this
-// because once we've constructed a BrowserThemePack through the
-// BuildFromExtension() interface, we WriteToDisk() on a thread other than the
-// UI thread that consumes a BrowserThemePack.
-class BrowserThemePack : public base::RefCountedThreadSafe<BrowserThemePack> {
- public:
- ~BrowserThemePack();
-
- // Builds the theme pack from all data from |extension|. This is often done
- // on a separate thread as it takes so long.
- static BrowserThemePack* BuildFromExtension(Extension* extension);
-
- // Builds the theme pack from a previously WriteToDisk(). This operation
- // should be relatively fast, as it should be an mmap() and some pointer
- // swizzling. Returns NULL on any error attempting to read |path|.
- static scoped_refptr<BrowserThemePack> BuildFromDataPack(
- FilePath path, const std::string& expected_id);
-
- // Builds a data pack on disk at |path| for future quick loading by
- // BuildFromDataPack(). Often (but not always) called from the file thread;
- // implementation should be threadsafe because neither thread will write to
- // |image_memory_| and the worker thread will keep a reference to prevent
- // destruction.
- bool WriteToDisk(FilePath path) const;
-
- // Returns data from the pack, or the default value if |id| doesn't
- // exist. These methods should only be called from the UI thread. (But this
- // isn't enforced because of unit tests).
- bool GetTint(int id, color_utils::HSL* hsl) const;
- bool GetColor(int id, SkColor* color) const;
- bool GetDisplayProperty(int id, int* result) const;
- SkBitmap* GetBitmapNamed(int id) const;
- RefCountedMemory* GetRawData(int id) const;
-
- // Whether this theme provides an image for |id|.
- bool HasCustomImage(int id) const;
-
- private:
- friend class BrowserThemePackTest;
-
- // Cached images. We cache all retrieved and generated bitmaps and keep
- // track of the pointers. We own these and will delete them when we're done
- // using them.
- typedef std::map<int, SkBitmap*> ImageCache;
-
- // The raw PNG memory associated with a certain id.
- typedef std::map<int, scoped_refptr<RefCountedMemory> > RawImages;
-
- // Default. Everything is empty.
- BrowserThemePack();
-
- // Builds a header ready to write to disk.
- void BuildHeader(Extension* extension);
-
- // Transforms the JSON tint values into their final versions in the |tints_|
- // array.
- void BuildTintsFromJSON(DictionaryValue* tints_value);
-
- // Transforms the JSON color values into their final versions in the
- // |colors_| array and also fills in unspecified colors based on tint values.
- void BuildColorsFromJSON(DictionaryValue* color_value);
-
- // Implementation details of BuildColorsFromJSON().
- void ReadColorsFromJSON(DictionaryValue* colors_value,
- std::map<int, SkColor>* temp_colors);
- void GenerateMissingColors(std::map<int, SkColor>* temp_colors);
-
- // Transforms the JSON display properties into |display_properties_|.
- void BuildDisplayPropertiesFromJSON(DictionaryValue* display_value);
-
- // Parses the image names out of an extension.
- void ParseImageNamesFromJSON(DictionaryValue* images_value,
- FilePath images_path,
- std::map<int, FilePath>* file_paths) const;
-
- // Loads the unmodified bitmaps packed in the extension to SkBitmaps.
- void LoadRawBitmapsTo(const std::map<int, FilePath>& file_paths,
- ImageCache* raw_bitmaps);
-
- // Creates tinted and composited frame images. Source and destination is
- // |bitmaps|.
- void GenerateFrameImages(ImageCache* bitmaps) const;
-
- // Generates button images tinted with |button_tint| and places them in
- // processed_bitmaps.
- void GenerateTintedButtons(color_utils::HSL button_tint,
- ImageCache* processed_bitmaps) const;
-
- // Generates the semi-transparent tab background images, putting the results
- // in |bitmaps|. Must be called after GenerateFrameImages().
- void GenerateTabBackgroundImages(ImageCache* bitmaps) const;
-
- // Takes all the SkBitmaps in |image_cache_|, encodes them as PNGs and places
- // them in |image_memory_|.
- void RepackImageCacheToImageMemory();
-
- // Takes all images in |source| and puts them in |destination|, freeing any
- // image already in |destination| that |source| would overwrite.
- void MergeImageCaches(const ImageCache& source,
- ImageCache* destination) const;
-
- // Retrieves the tint OR the default tint. Unlike the public interface, we
- // always need to return a reasonable tint here, instead of partially
- // querying if the tint exists.
- color_utils::HSL GetTintInternal(int id) const;
-
- // Data pack, if we have one.
- scoped_ptr<base::DataPack> data_pack_;
-
- // All structs written to disk need to be packed; no alignment tricks here,
- // please.
-#pragma pack(push,1)
- // Header that is written to disk.
- struct BrowserThemePackHeader {
- // Numeric version to make sure we're compatible in the future.
- int32 version;
-
- // 1 if little_endian. 0 if big_endian. On mismatch, abort load.
- int32 little_endian;
-
- // theme_id without NULL terminator.
- uint8 theme_id[16];
- } *header_;
-
- // The remaining structs represent individual entries in an array. For the
- // following three structs, BrowserThemePack will either allocate an array or
- // will point directly to mmapped data.
- struct TintEntry {
- int32 id;
- double h;
- double s;
- double l;
- } *tints_;
-
- struct ColorPair {
- int32 id;
- SkColor color;
- } *colors_;
-
- struct DisplayPropertyPair {
- int32 id;
- int32 property;
- } *display_properties_;
-#pragma pack(pop)
-
- // References to raw PNG data. This map isn't touched when |data_pack_| is
- // non-NULL; |image_memory_| is only filled during BuildFromExtension(). Any
- // image data that needs to be written to the DataPack during WriteToDisk()
- // needs to be in |image_memory_|.
- RawImages image_memory_;
-
- // Tinted (or otherwise prepared) images for passing out. BrowserThemePack
- // owns all these images. This cache isn't touched when we write our data to
- // a DataPack.
- mutable ImageCache image_cache_;
-
- DISALLOW_COPY_AND_ASSIGN(BrowserThemePack);
-};
-
-#endif // CHROME_BROWSER_BROWSER_THEME_PACK_H_
diff --git a/chrome/browser/browser_theme_pack_unittest.cc b/chrome/browser/browser_theme_pack_unittest.cc
deleted file mode 100644
index 1c9081c..0000000
--- a/chrome/browser/browser_theme_pack_unittest.cc
+++ /dev/null
@@ -1,335 +0,0 @@
-// 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.
-
-#include "chrome/browser/browser_theme_pack.h"
-
-#include "app/gfx/color_utils.h"
-#include "app/theme_provider.h"
-#include "base/file_util.h"
-#include "base/json/json_reader.h"
-#include "base/path_service.h"
-#include "base/scoped_temp_dir.h"
-#include "base/values.h"
-#include "chrome/browser/theme_resources_util.h"
-#include "chrome/browser/browser_theme_provider.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/json_value_serializer.h"
-#include "grit/theme_resources.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class BrowserThemePackTest : public ::testing::Test {
- public:
- BrowserThemePackTest() : theme_pack_(new BrowserThemePack) { }
-
- // Transformation for link underline colors.
- SkColor BuildThirdOpacity(SkColor color_link) {
- return SkColorSetA(color_link, SkColorGetA(color_link) / 3);
- }
-
- void GenerateDefaultFrameColor(std::map<int, SkColor>* colors,
- int color, int tint) {
- (*colors)[color] = HSLShift(
- BrowserThemeProvider::GetDefaultColor(
- BrowserThemeProvider::COLOR_FRAME),
- BrowserThemeProvider::GetDefaultTint(tint));
- }
-
- // Returns a mapping from each COLOR_* constant to the default value for this
- // constant. Callers get this map, and then modify expected values and then
- // run the resulting thing through VerifyColorMap().
- std::map<int, SkColor> GetDefaultColorMap() {
- std::map<int, SkColor> colors;
- for (int i = BrowserThemeProvider::COLOR_FRAME;
- i <= BrowserThemeProvider::COLOR_BUTTON_BACKGROUND; ++i) {
- colors[i] = BrowserThemeProvider::GetDefaultColor(i);
- }
-
- GenerateDefaultFrameColor(&colors, BrowserThemeProvider::COLOR_FRAME,
- BrowserThemeProvider::TINT_FRAME);
- GenerateDefaultFrameColor(&colors,
- BrowserThemeProvider::COLOR_FRAME_INACTIVE,
- BrowserThemeProvider::TINT_FRAME_INACTIVE);
- GenerateDefaultFrameColor(&colors,
- BrowserThemeProvider::COLOR_FRAME_INCOGNITO,
- BrowserThemeProvider::TINT_FRAME_INCOGNITO);
- GenerateDefaultFrameColor(
- &colors,
- BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE,
- BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE);
-
- return colors;
- }
-
- void VerifyColorMap(const std::map<int, SkColor>& color_map) {
- for (std::map<int, SkColor>::const_iterator it = color_map.begin();
- it != color_map.end(); ++it) {
- SkColor color = BrowserThemeProvider::GetDefaultColor(it->first);
- theme_pack_->GetColor(it->first, &color);
- EXPECT_EQ(it->second, color) << "Color id = " << it->first;
- }
- }
-
- void LoadColorJSON(const std::string& json) {
- scoped_ptr<Value> value(base::JSONReader::Read(json, false));
- ASSERT_TRUE(value->IsType(Value::TYPE_DICTIONARY));
- theme_pack_->BuildColorsFromJSON(
- static_cast<DictionaryValue*>(value.get()));
- }
-
- void LoadTintJSON(const std::string& json) {
- scoped_ptr<Value> value(base::JSONReader::Read(json, false));
- ASSERT_TRUE(value->IsType(Value::TYPE_DICTIONARY));
- theme_pack_->BuildTintsFromJSON(
- static_cast<DictionaryValue*>(value.get()));
- }
-
- void LoadDisplayPropertiesJSON(const std::string& json) {
- scoped_ptr<Value> value(base::JSONReader::Read(json, false));
- ASSERT_TRUE(value->IsType(Value::TYPE_DICTIONARY));
- theme_pack_->BuildDisplayPropertiesFromJSON(
- static_cast<DictionaryValue*>(value.get()));
- }
-
- void ParseImageNames(const std::string& json,
- std::map<int, FilePath>* out_file_paths) {
- scoped_ptr<Value> value(base::JSONReader::Read(json, false));
- ASSERT_TRUE(value->IsType(Value::TYPE_DICTIONARY));
- theme_pack_->ParseImageNamesFromJSON(
- static_cast<DictionaryValue*>(value.get()),
- FilePath(), out_file_paths);
- }
-
- FilePath GetStarGazingPath() {
- FilePath test_path;
- if (!PathService::Get(chrome::DIR_TEST_DATA, &test_path)) {
- NOTREACHED();
- return test_path;
- }
-
- test_path = test_path.AppendASCII("profiles");
- test_path = test_path.AppendASCII("complex_theme");
- test_path = test_path.AppendASCII("Default");
- test_path = test_path.AppendASCII("Extensions");
- test_path = test_path.AppendASCII("mblmlcbknbnfebdfjnolmcapmdofhmme");
- test_path = test_path.AppendASCII("1.1");
- return FilePath(test_path);
- }
-
- // Verifies the data in star gazing. We do this multiple times for different
- // BrowserThemePack objects to make sure it works in generated and mmapped
- // mode correctly.
- void VerifyStarGazing(BrowserThemePack* pack) {
- // First check that values we know exist, exist.
- SkColor color;
- EXPECT_TRUE(pack->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT,
- &color));
- EXPECT_EQ(SK_ColorBLACK, color);
-
- EXPECT_TRUE(pack->GetColor(BrowserThemeProvider::COLOR_NTP_BACKGROUND,
- &color));
- EXPECT_EQ(SkColorSetRGB(57, 137, 194), color);
-
- color_utils::HSL expected = { 0.6, 0.553, 0.5 };
- color_utils::HSL actual;
- EXPECT_TRUE(pack->GetTint(BrowserThemeProvider::TINT_BUTTONS, &actual));
- EXPECT_DOUBLE_EQ(expected.h, actual.h);
- EXPECT_DOUBLE_EQ(expected.s, actual.s);
- EXPECT_DOUBLE_EQ(expected.l, actual.l);
-
- int val;
- EXPECT_TRUE(pack->GetDisplayProperty(
- BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT, &val));
- EXPECT_EQ(BrowserThemeProvider::ALIGN_TOP, val);
-
- EXPECT_TRUE(pack->HasCustomImage(IDR_THEME_FRAME));
-
- // Make sure we don't have phantom data.
- EXPECT_FALSE(pack->GetColor(BrowserThemeProvider::COLOR_CONTROL_BACKGROUND,
- &color));
- EXPECT_FALSE(pack->GetTint(BrowserThemeProvider::TINT_FRAME, &actual));
- }
-
- scoped_refptr<BrowserThemePack> theme_pack_;
-};
-
-
-TEST_F(BrowserThemePackTest, DeriveUnderlineLinkColor) {
- // If we specify a link color, but don't specify the underline color, the
- // theme provider should create one.
- std::string color_json = "{ \"ntp_link\": [128, 128, 128],"
- " \"ntp_section_link\": [128, 128, 128] }";
- LoadColorJSON(color_json);
-
- std::map<int, SkColor> colors = GetDefaultColorMap();
- SkColor link_color = SkColorSetRGB(128, 128, 128);
- colors[BrowserThemeProvider::COLOR_NTP_LINK] = link_color;
- colors[BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE] =
- BuildThirdOpacity(link_color);
- colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK] = link_color;
- colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE] =
- BuildThirdOpacity(link_color);
-
- VerifyColorMap(colors);
-}
-
-TEST_F(BrowserThemePackTest, ProvideUnderlineLinkColor) {
- // If we specify the underline color, it shouldn't try to generate one.x
- std::string color_json = "{ \"ntp_link\": [128, 128, 128],"
- " \"ntp_link_underline\": [255, 255, 255],"
- " \"ntp_section_link\": [128, 128, 128],"
- " \"ntp_section_link_underline\": [255, 255, 255]"
- "}";
- LoadColorJSON(color_json);
-
- std::map<int, SkColor> colors = GetDefaultColorMap();
- SkColor link_color = SkColorSetRGB(128, 128, 128);
- SkColor underline_color = SkColorSetRGB(255, 255, 255);
- colors[BrowserThemeProvider::COLOR_NTP_LINK] = link_color;
- colors[BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE] = underline_color;
- colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK] = link_color;
- colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE] =
- underline_color;
-
- VerifyColorMap(colors);
-}
-
-TEST_F(BrowserThemePackTest, UseSectionColorAsNTPHeader) {
- std::string color_json = "{ \"ntp_section\": [190, 190, 190] }";
- LoadColorJSON(color_json);
-
- std::map<int, SkColor> colors = GetDefaultColorMap();
- SkColor ntp_color = SkColorSetRGB(190, 190, 190);
- colors[BrowserThemeProvider::COLOR_NTP_HEADER] = ntp_color;
- colors[BrowserThemeProvider::COLOR_NTP_SECTION] = ntp_color;
- VerifyColorMap(colors);
-}
-
-TEST_F(BrowserThemePackTest, ProvideNtpHeaderColor) {
- std::string color_json = "{ \"ntp_header\": [120, 120, 120], "
- " \"ntp_section\": [190, 190, 190] }";
- LoadColorJSON(color_json);
-
- std::map<int, SkColor> colors = GetDefaultColorMap();
- SkColor ntp_header = SkColorSetRGB(120, 120, 120);
- SkColor ntp_section = SkColorSetRGB(190, 190, 190);
- colors[BrowserThemeProvider::COLOR_NTP_HEADER] = ntp_header;
- colors[BrowserThemeProvider::COLOR_NTP_SECTION] = ntp_section;
- VerifyColorMap(colors);
-}
-
-TEST_F(BrowserThemePackTest, CanReadTints) {
- std::string tint_json = "{ \"buttons\": [ 0.5, 0.5, 0.5 ] }";
- LoadTintJSON(tint_json);
-
- color_utils::HSL expected = { 0.5, 0.5, 0.5 };
- color_utils::HSL actual = { -1, -1, -1 };
- EXPECT_TRUE(theme_pack_->GetTint(
- BrowserThemeProvider::TINT_BUTTONS, &actual));
- EXPECT_DOUBLE_EQ(expected.h, actual.h);
- EXPECT_DOUBLE_EQ(expected.s, actual.s);
- EXPECT_DOUBLE_EQ(expected.l, actual.l);
-}
-
-TEST_F(BrowserThemePackTest, CanReadDisplayProperties) {
- std::string json = "{ \"ntp_background_alignment\": \"bottom\", "
- " \"ntp_background_repeat\": \"repeat-x\", "
- " \"ntp_logo_alternate\": 0 }";
- LoadDisplayPropertiesJSON(json);
-
- int out_val;
- EXPECT_TRUE(theme_pack_->GetDisplayProperty(
- BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT, &out_val));
- EXPECT_EQ(BrowserThemeProvider::ALIGN_BOTTOM, out_val);
-
- EXPECT_TRUE(theme_pack_->GetDisplayProperty(
- BrowserThemeProvider::NTP_BACKGROUND_TILING, &out_val));
- EXPECT_EQ(BrowserThemeProvider::REPEAT_X, out_val);
-
- EXPECT_TRUE(theme_pack_->GetDisplayProperty(
- BrowserThemeProvider::NTP_LOGO_ALTERNATE, &out_val));
- EXPECT_EQ(0, out_val);
-}
-
-TEST_F(BrowserThemePackTest, CanParsePaths) {
- std::string tint_json = "{ \"theme_button_background\": \"one\", "
- " \"theme_toolbar\": \"two\" }";
- std::map<int, FilePath> out_file_paths;
- ParseImageNames(tint_json, &out_file_paths);
-
- EXPECT_EQ(2u, out_file_paths.size());
- EXPECT_TRUE(FilePath(FILE_PATH_LITERAL("one")) == out_file_paths[
- ThemeResourcesUtil::GetId("theme_button_background")]);
- EXPECT_TRUE(FilePath(FILE_PATH_LITERAL("two")) ==
- out_file_paths[ThemeResourcesUtil::GetId("theme_toolbar")]);
-}
-
-TEST_F(BrowserThemePackTest, InvalidColors) {
- std::string invalid_color = "{ \"toolbar\": [\"dog\", \"cat\", [12]], "
- " \"sound\": \"woof\" }";
- LoadColorJSON(invalid_color);
- std::map<int, SkColor> colors = GetDefaultColorMap();
- VerifyColorMap(colors);
-}
-
-TEST_F(BrowserThemePackTest, InvalidTints) {
- std::string invalid_tints = "{ \"buttons\": [ \"dog\", \"cat\", [\"x\"]], "
- " \"invalid\": \"entry\" }";
- LoadTintJSON(invalid_tints);
-
- // We shouldn't have a buttons tint, as it was invalid.
- color_utils::HSL actual = { -1, -1, -1 };
- EXPECT_FALSE(theme_pack_->GetTint(BrowserThemeProvider::TINT_BUTTONS,
- &actual));
-}
-
-TEST_F(BrowserThemePackTest, InvalidDisplayProperties) {
- std::string invalid_properties = "{ \"ntp_background_alignment\": [15], "
- " \"junk\": [15.3] }";
- LoadDisplayPropertiesJSON(invalid_properties);
-
- int out_val;
- EXPECT_FALSE(theme_pack_->GetDisplayProperty(
- BrowserThemeProvider::NTP_BACKGROUND_ALIGNMENT, &out_val));
-}
-
-// TODO(erg): This test should actually test more of the built resources from
-// the extension data, but for now, exists so valgrind can test some of the
-// tricky memory stuff that BrowserThemePack does.
-TEST_F(BrowserThemePackTest, CanBuildAndReadPack) {
- ScopedTempDir dir;
- ASSERT_TRUE(dir.CreateUniqueTempDir());
- FilePath file = dir.path().Append(FILE_PATH_LITERAL("data.pak"));
-
- // Part 1: Build the pack from an extension.
- {
- FilePath star_gazing_path = GetStarGazingPath();
- Extension extension(star_gazing_path);
-
- FilePath manifest_path =
- star_gazing_path.AppendASCII("manifest.json");
- std::string error;
- JSONFileValueSerializer serializer(manifest_path);
- scoped_ptr<DictionaryValue> valid_value(
- static_cast<DictionaryValue*>(serializer.Deserialize(&error)));
- EXPECT_EQ("", error);
- ASSERT_TRUE(valid_value.get());
- ASSERT_TRUE(extension.InitFromValue(*valid_value, true, &error));
- ASSERT_EQ("", error);
-
- scoped_refptr<BrowserThemePack> pack =
- BrowserThemePack::BuildFromExtension(&extension);
- ASSERT_TRUE(pack.get());
- ASSERT_TRUE(pack->WriteToDisk(file));
- VerifyStarGazing(pack.get());
- }
-
- // Part 2: Try to read back the data pack that we just wrote to disk.
- {
- scoped_refptr<BrowserThemePack> pack =
- BrowserThemePack::BuildFromDataPack(
- file, "mblmlcbknbnfebdfjnolmcapmdofhmme");
- ASSERT_TRUE(pack.get());
- VerifyStarGazing(pack.get());
- }
-}
diff --git a/chrome/browser/browser_theme_provider.cc b/chrome/browser/browser_theme_provider.cc
index 5a47772..aceedf1 100644
--- a/chrome/browser/browser_theme_provider.cc
+++ b/chrome/browser/browser_theme_provider.cc
@@ -13,7 +13,6 @@
#include "base/values.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
-#include "chrome/browser/browser_theme_pack.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/metrics/user_metrics.h"
@@ -37,6 +36,50 @@
#include "app/win_util.h"
#endif
+// Strings used by themes to identify colors for different parts of our UI.
+const char* BrowserThemeProvider::kColorFrame = "frame";
+const char* BrowserThemeProvider::kColorFrameInactive = "frame_inactive";
+const char* BrowserThemeProvider::kColorFrameIncognito = "frame_incognito";
+const char* BrowserThemeProvider::kColorFrameIncognitoInactive =
+ "frame_incognito_inactive";
+const char* BrowserThemeProvider::kColorToolbar = "toolbar";
+const char* BrowserThemeProvider::kColorTabText = "tab_text";
+const char* BrowserThemeProvider::kColorBackgroundTabText =
+ "tab_background_text";
+const char* BrowserThemeProvider::kColorBookmarkText = "bookmark_text";
+const char* BrowserThemeProvider::kColorNTPBackground = "ntp_background";
+const char* BrowserThemeProvider::kColorNTPText = "ntp_text";
+const char* BrowserThemeProvider::kColorNTPLink = "ntp_link";
+const char* BrowserThemeProvider::kColorNTPLinkUnderline = "ntp_link_underline";
+const char* BrowserThemeProvider::kColorNTPHeader = "ntp_header";
+const char* BrowserThemeProvider::kColorNTPSection = "ntp_section";
+const char* BrowserThemeProvider::kColorNTPSectionText = "ntp_section_text";
+const char* BrowserThemeProvider::kColorNTPSectionLink = "ntp_section_link";
+const char* BrowserThemeProvider::kColorNTPSectionLinkUnderline =
+ "ntp_section_link_underline";
+const char* BrowserThemeProvider::kColorControlBackground =
+ "control_background";
+const char* BrowserThemeProvider::kColorButtonBackground = "button_background";
+
+// Strings used by themes to identify tints to apply to different parts of
+// our UI. The frame tints apply to the frame color and produce the
+// COLOR_FRAME* colors.
+const char* BrowserThemeProvider::kTintButtons = "buttons";
+const char* BrowserThemeProvider::kTintFrame = "frame";
+const char* BrowserThemeProvider::kTintFrameInactive = "frame_inactive";
+const char* BrowserThemeProvider::kTintFrameIncognito = "frame_incognito";
+const char* BrowserThemeProvider::kTintFrameIncognitoInactive =
+ "frame_incognito_inactive";
+const char* BrowserThemeProvider::kTintBackgroundTab = "background_tab";
+
+// Strings used by themes to identify miscellaneous numerical properties.
+const char* BrowserThemeProvider::kDisplayPropertyNTPAlignment =
+ "ntp_background_alignment";
+const char* BrowserThemeProvider::kDisplayPropertyNTPTiling =
+ "ntp_background_repeat";
+const char* BrowserThemeProvider::kDisplayPropertyNTPInverseLogo =
+ "ntp_logo_alternate";
+
// Strings used in alignment properties.
const char* BrowserThemeProvider::kAlignmentTop = "top";
const char* BrowserThemeProvider::kAlignmentBottom = "bottom";
@@ -49,52 +92,68 @@ const char* BrowserThemeProvider::kTilingRepeatX = "repeat-x";
const char* BrowserThemeProvider::kTilingRepeatY = "repeat-y";
const char* BrowserThemeProvider::kTilingRepeat = "repeat";
-// Saved default values.
-const char* BrowserThemeProvider::kDefaultThemeID = "";
-
-namespace {
-
-SkColor TintForUnderline(SkColor input) {
- return SkColorSetA(input, SkColorGetA(input) / 3);
-}
-
// Default colors.
-const SkColor kDefaultColorFrame = SkColorSetRGB(77, 139, 217);
-const SkColor kDefaultColorFrameInactive = SkColorSetRGB(152, 188, 233);
-const SkColor kDefaultColorFrameIncognito = SkColorSetRGB(83, 106, 139);
-const SkColor kDefaultColorFrameIncognitoInactive =
+const SkColor BrowserThemeProvider::kDefaultColorFrame =
+ SkColorSetRGB(77, 139, 217);
+const SkColor BrowserThemeProvider::kDefaultColorFrameInactive =
+ SkColorSetRGB(152, 188, 233);
+const SkColor BrowserThemeProvider::kDefaultColorFrameIncognito =
+ SkColorSetRGB(83, 106, 139);
+const SkColor BrowserThemeProvider::kDefaultColorFrameIncognitoInactive =
SkColorSetRGB(126, 139, 156);
-const SkColor kDefaultColorToolbar = SkColorSetRGB(210, 225, 246);
-const SkColor kDefaultColorTabText = SK_ColorBLACK;
-const SkColor kDefaultColorBackgroundTabText = SkColorSetRGB(64, 64, 64);
-const SkColor kDefaultColorBookmarkText = SkColorSetRGB(18, 50, 114);
+const SkColor BrowserThemeProvider::kDefaultColorToolbar =
+ SkColorSetRGB(210, 225, 246);
+const SkColor BrowserThemeProvider::kDefaultColorTabText = SK_ColorBLACK;
+const SkColor BrowserThemeProvider::kDefaultColorBackgroundTabText =
+ SkColorSetRGB(64, 64, 64);
+const SkColor BrowserThemeProvider::kDefaultColorBookmarkText =
+ SkColorSetRGB(18, 50, 114);
#if defined(OS_WIN)
-const SkColor kDefaultColorNTPBackground =
+const SkColor BrowserThemeProvider::kDefaultColorNTPBackground =
color_utils::GetSysSkColor(COLOR_WINDOW);
-const SkColor kDefaultColorNTPText =
+const SkColor BrowserThemeProvider::kDefaultColorNTPText =
color_utils::GetSysSkColor(COLOR_WINDOWTEXT);
-const SkColor kDefaultColorNTPLink =
+const SkColor BrowserThemeProvider::kDefaultColorNTPLink =
color_utils::GetSysSkColor(COLOR_HOTLIGHT);
#else
// TODO(beng): source from theme provider.
-const SkColor kDefaultColorNTPBackground = SK_ColorWHITE;
-const SkColor kDefaultColorNTPText = SK_ColorBLACK;
-const SkColor kDefaultColorNTPLink = SkColorSetRGB(6, 55, 116);
+const SkColor BrowserThemeProvider::kDefaultColorNTPBackground = SK_ColorWHITE;
+const SkColor BrowserThemeProvider::kDefaultColorNTPText = SK_ColorBLACK;
+const SkColor BrowserThemeProvider::kDefaultColorNTPLink =
+ SkColorSetRGB(6, 55, 116);
#endif
-const SkColor kDefaultColorNTPHeader = SkColorSetRGB(75, 140, 220);
-const SkColor kDefaultColorNTPSection = SkColorSetRGB(229, 239, 254);
-const SkColor kDefaultColorNTPSectionText = SK_ColorBLACK;
-const SkColor kDefaultColorNTPSectionLink = SkColorSetRGB(6, 55, 116);
-const SkColor kDefaultColorControlBackground = SkColorSetARGB(0, 0, 0, 0);
-const SkColor kDefaultColorButtonBackground = SkColorSetARGB(0, 0, 0, 0);
+const SkColor BrowserThemeProvider::kDefaultColorNTPHeader =
+ SkColorSetRGB(75, 140, 220);
+const SkColor BrowserThemeProvider::kDefaultColorNTPSection =
+ SkColorSetRGB(229, 239, 254);
+const SkColor BrowserThemeProvider::kDefaultColorNTPSectionText = SK_ColorBLACK;
+const SkColor BrowserThemeProvider::kDefaultColorNTPSectionLink =
+ SkColorSetRGB(6, 55, 116);
+const SkColor BrowserThemeProvider::kDefaultColorControlBackground =
+ SkColorSetARGB(0, 0, 0, 0);
+const SkColor BrowserThemeProvider::kDefaultColorButtonBackground =
+ SkColorSetARGB(0, 0, 0, 0);
// Default tints.
-const color_utils::HSL kDefaultTintButtons = { -1, -1, -1 };
-const color_utils::HSL kDefaultTintFrame = { -1, -1, -1 };
-const color_utils::HSL kDefaultTintFrameInactive = { -1, -1, 0.75f };
-const color_utils::HSL kDefaultTintFrameIncognito = { -1, 0.2f, 0.35f };
-const color_utils::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3f, 0.6f };
-const color_utils::HSL kDefaultTintBackgroundTab = { -1, 0.5, 0.75 };
+const color_utils::HSL BrowserThemeProvider::kDefaultTintButtons =
+ { -1, -1, -1 };
+const color_utils::HSL BrowserThemeProvider::kDefaultTintFrame = { -1, -1, -1 };
+const color_utils::HSL BrowserThemeProvider::kDefaultTintFrameInactive =
+ { -1, -1, 0.75f };
+const color_utils::HSL BrowserThemeProvider::kDefaultTintFrameIncognito =
+ { -1, 0.2f, 0.35f };
+const color_utils::HSL
+ BrowserThemeProvider::kDefaultTintFrameIncognitoInactive =
+ { -1, 0.3f, 0.6f };
+const color_utils::HSL BrowserThemeProvider::kDefaultTintBackgroundTab =
+ { -1, 0.5, 0.75 };
+
+// Saved default values.
+const char* BrowserThemeProvider::kDefaultThemeID = "";
+
+Lock BrowserThemeProvider::themed_image_cache_lock_;
+
+namespace {
// Default display properties.
const int kDefaultDisplayPropertyNTPAlignment =
@@ -107,6 +166,35 @@ const int kDefaultDisplayPropertyNTPInverseLogo = 0;
// OpaqueBrowserFrameView.
const int kRestoredTabVerticalOffset = 15;
+// The image resources that will be tinted by the 'button' tint value.
+const int kToolbarButtonIDs[] = {
+ IDR_BACK, IDR_BACK_D, IDR_BACK_H, IDR_BACK_P,
+ IDR_FORWARD, IDR_FORWARD_D, IDR_FORWARD_H, IDR_FORWARD_P,
+ IDR_RELOAD, IDR_RELOAD_H, IDR_RELOAD_P,
+ IDR_HOME, IDR_HOME_H, IDR_HOME_P,
+ IDR_STAR, IDR_STAR_NOBORDER, IDR_STAR_NOBORDER_CENTER, IDR_STAR_D, IDR_STAR_H,
+ IDR_STAR_P,
+ IDR_STARRED, IDR_STARRED_NOBORDER, IDR_STARRED_NOBORDER_CENTER, IDR_STARRED_H,
+ IDR_STARRED_P,
+ IDR_GO, IDR_GO_NOBORDER, IDR_GO_NOBORDER_CENTER, IDR_GO_H, IDR_GO_P,
+ IDR_STOP, IDR_STOP_NOBORDER, IDR_STOP_NOBORDER_CENTER, IDR_STOP_H, IDR_STOP_P,
+ IDR_MENU_BOOKMARK,
+ IDR_MENU_PAGE, IDR_MENU_PAGE_RTL,
+ IDR_MENU_CHROME, IDR_MENU_CHROME_RTL,
+ IDR_MENU_DROPARROW,
+ IDR_THROBBER, IDR_THROBBER_WAITING, IDR_THROBBER_LIGHT,
+ IDR_LOCATIONBG
+};
+
+bool HasButtonImage(int toolbar_button_id) {
+ static std::map<int, bool> button_images;
+ if (button_images.empty()) {
+ for (size_t i = 0; i < arraysize(kToolbarButtonIDs); ++i)
+ button_images[kToolbarButtonIDs[i]] = true;
+ }
+ return button_images.count(toolbar_button_id) > 0;
+}
+
// The image resources we will allow people to theme.
const int kThemeableImages[] = {
IDR_THEME_FRAME,
@@ -134,21 +222,49 @@ bool HasThemeableImage(int themeable_image_id) {
return themeable_images.count(themeable_image_id) > 0;
}
-// Writes the theme pack to disk on a separate thread.
-class WritePackToDiskTask : public Task {
+
+class WriteImagesToDiskTask : public Task {
public:
- WritePackToDiskTask(BrowserThemePack* pack, const FilePath& path)
- : theme_pack_(pack), pack_path_(path) {}
+ WriteImagesToDiskTask(
+ const BrowserThemeProvider::ImagesDiskCache& images_disk_cache,
+ const BrowserThemeProvider::ImageCache& themed_image_cache) :
+ images_disk_cache_(images_disk_cache),
+ themed_image_cache_(themed_image_cache) {
+ }
virtual void Run() {
- if (!theme_pack_->WriteToDisk(pack_path_)) {
- NOTREACHED() << "Could not write theme pack to disk";
+ AutoLock lock(BrowserThemeProvider::themed_image_cache_lock_);
+ for (BrowserThemeProvider::ImagesDiskCache::const_iterator iter(
+ images_disk_cache_.begin()); iter != images_disk_cache_.end();
+ ++iter) {
+ FilePath image_path = iter->first;
+ BrowserThemeProvider::ImageCache::const_iterator themed_iter =
+ themed_image_cache_.find(iter->second);
+ if (themed_iter != themed_image_cache_.end()) {
+ SkBitmap* bitmap = themed_iter->second;
+ std::vector<unsigned char> image_data;
+ if (!gfx::PNGCodec::EncodeBGRASkBitmap(*bitmap, false, &image_data)) {
+ NOTREACHED() << "Image file could not be encoded.";
+ return;
+ }
+ const char* image_data_ptr =
+ reinterpret_cast<const char*>(&image_data[0]);
+ if (!file_util::WriteFile(image_path,
+ image_data_ptr, image_data.size())) {
+ NOTREACHED() << "Image file could not be written to disk.";
+ return;
+ }
+ } else {
+ NOTREACHED() << "Themed image missing from cache.";
+ return;
+ }
}
}
private:
- scoped_refptr<BrowserThemePack> theme_pack_;
- FilePath pack_path_;
+ // References to data held in the BrowserThemeProvider.
+ const BrowserThemeProvider::ImagesDiskCache& images_disk_cache_;
+ const BrowserThemeProvider::ImageCache& themed_image_cache_;
};
} // namespace
@@ -159,13 +275,32 @@ bool BrowserThemeProvider::IsThemeableImage(int resource_id) {
BrowserThemeProvider::BrowserThemeProvider()
: rb_(ResourceBundle::GetSharedInstance()),
- profile_(NULL) {
+ profile_(NULL),
+ process_images_(false) {
// Initialize the themeable image map so we can use it on other threads.
HasThemeableImage(0);
+ resource_names_[IDR_THEME_FRAME] = "theme_frame";
+ resource_names_[IDR_THEME_FRAME_INACTIVE] = "theme_frame_inactive";
+ resource_names_[IDR_THEME_FRAME_OVERLAY] = "theme_frame_overlay";
+ resource_names_[IDR_THEME_FRAME_OVERLAY_INACTIVE] =
+ "theme_frame_overlay_inactive";
+ resource_names_[IDR_THEME_FRAME_INCOGNITO] = "theme_frame_incognito";
+ resource_names_[IDR_THEME_FRAME_INCOGNITO_INACTIVE] =
+ "theme_frame_incognito_inactive";
+ resource_names_[IDR_THEME_TAB_BACKGROUND] = "theme_tab_background";
+ resource_names_[IDR_THEME_TAB_BACKGROUND_INCOGNITO] =
+ "theme_tab_background_incognito";
+ resource_names_[IDR_THEME_TOOLBAR] = "theme_toolbar";
+ resource_names_[IDR_THEME_TAB_BACKGROUND_V] = "theme_tab_background_v";
+ resource_names_[IDR_THEME_NTP_BACKGROUND] = "theme_ntp_background";
+ resource_names_[IDR_THEME_BUTTON_BACKGROUND] = "theme_button_background";
+ resource_names_[IDR_THEME_NTP_ATTRIBUTION] = "theme_ntp_attribution";
+ resource_names_[IDR_THEME_WINDOW_CONTROL_BACKGROUND] =
+ "theme_window_control_background";
}
BrowserThemeProvider::~BrowserThemeProvider() {
- FreePlatformCaches();
+ ClearCaches();
RemoveUnusedThemes();
}
@@ -174,37 +309,120 @@ void BrowserThemeProvider::Init(Profile* profile) {
DCHECK(CalledOnValidThread());
profile_ = profile;
+ image_dir_ = profile_->GetPath().Append(chrome::kThemeImagesDirname);
+ if (!file_util::PathExists(image_dir_))
+ file_util::CreateDirectory(image_dir_);
+
LoadThemePrefs();
}
SkBitmap* BrowserThemeProvider::GetBitmapNamed(int id) const {
DCHECK(CalledOnValidThread());
- SkBitmap* bitmap = NULL;
-
- if (theme_pack_.get())
- bitmap = theme_pack_->GetBitmapNamed(id);
-
- if (!bitmap)
- bitmap = rb_.GetBitmapNamed(id);
+ // First check to see if the Skia image is in the themed cache. The themed
+ // cache is not changed in this method, so it can remain unlocked.
+ ImageCache::const_iterator themed_iter = themed_image_cache_.find(id);
+ if (themed_iter != themed_image_cache_.end())
+ return themed_iter->second;
+
+ // If Skia image is not in themed cache, check regular cache, and possibly
+ // generate and store.
+ ImageCache::const_iterator image_iter = image_cache_.find(id);
+ if (image_iter != image_cache_.end())
+ return image_iter->second;
+
+ scoped_ptr<SkBitmap> result;
+
+ // Try to load the image from the extension.
+ result.reset(LoadThemeBitmap(id));
+
+ // If we still don't have an image, load it from resourcebundle.
+ if (!result.get())
+ result.reset(new SkBitmap(*rb_.GetBitmapNamed(id)));
+
+ if (result.get()) {
+ // If the requested image is part of the toolbar button set, and we have
+ // a provided tint for that set, tint it appropriately.
+ if (HasButtonImage(id) && tints_.count(kTintButtons)) {
+ SkBitmap* tinted =
+ new SkBitmap(TintBitmap(*result.release(), TINT_BUTTONS));
+ result.reset(tinted);
+ }
- return bitmap;
+ // We loaded successfully. Cache the bitmap.
+ image_cache_[id] = result.get();
+ return result.release();
+ } else {
+ NOTREACHED() << "Failed to load a requested image";
+ return NULL;
+ }
}
SkColor BrowserThemeProvider::GetColor(int id) const {
DCHECK(CalledOnValidThread());
- SkColor color;
- if (theme_pack_.get() && theme_pack_->GetColor(id, &color))
- return color;
+ // Special-case NTP header - if the color isn't provided, we fall back to
+ // the section color.
+ if (id == COLOR_NTP_HEADER) {
+ ColorMap::const_iterator color_iter = colors_.find(kColorNTPHeader);
+ if (color_iter != colors_.end())
+ return color_iter->second;
+ color_iter = colors_.find(kColorNTPSection);
+ return (color_iter == colors_.end()) ?
+ GetDefaultColor(id) : color_iter->second;
+ }
+
+ // Special case the underline colors to use semi transparent in case not
+ // defined.
+ if (id == COLOR_NTP_SECTION_LINK_UNDERLINE) {
+ ColorMap::const_iterator color_iter =
+ colors_.find(kColorNTPSectionLinkUnderline);
+ if (color_iter != colors_.end())
+ return color_iter->second;
+ SkColor color_section_link = GetColor(COLOR_NTP_SECTION_LINK);
+ return SkColorSetA(color_section_link, SkColorGetA(color_section_link) / 3);
+ }
- return GetDefaultColor(id);
+ if (id == COLOR_NTP_LINK_UNDERLINE) {
+ ColorMap::const_iterator color_iter = colors_.find(kColorNTPLinkUnderline);
+ if (color_iter != colors_.end())
+ return color_iter->second;
+ SkColor color_link = GetColor(COLOR_NTP_LINK);
+ return SkColorSetA(color_link, SkColorGetA(color_link) / 3);
+ }
+
+ // TODO(glen): Figure out if we need to tint these. http://crbug.com/11578
+ ColorMap::const_iterator color_iter = colors_.find(GetColorKey(id));
+ return (color_iter == colors_.end()) ?
+ GetDefaultColor(id) : color_iter->second;
}
bool BrowserThemeProvider::GetDisplayProperty(int id, int* result) const {
- if (theme_pack_.get())
- return theme_pack_->GetDisplayProperty(id, result);
-
+ switch (id) {
+ case NTP_BACKGROUND_ALIGNMENT: {
+ DisplayPropertyMap::const_iterator display_iter =
+ display_properties_.find(kDisplayPropertyNTPAlignment);
+ *result = (display_iter == display_properties_.end()) ?
+ kDefaultDisplayPropertyNTPAlignment : display_iter->second;
+ return true;
+ }
+ case NTP_BACKGROUND_TILING: {
+ DisplayPropertyMap::const_iterator display_iter =
+ display_properties_.find(kDisplayPropertyNTPTiling);
+ *result = (display_iter == display_properties_.end()) ?
+ kDefaultDisplayPropertyNTPTiling : display_iter->second;
+ return true;
+ }
+ case NTP_LOGO_ALTERNATE: {
+ DisplayPropertyMap::const_iterator display_iter =
+ display_properties_.find(kDisplayPropertyNTPInverseLogo);
+ *result = (display_iter == display_properties_.end()) ?
+ kDefaultDisplayPropertyNTPInverseLogo : display_iter->second;
+ return true;
+ }
+ default:
+ NOTREACHED() << "Unknown property requested";
+ }
return false;
}
@@ -222,10 +440,15 @@ bool BrowserThemeProvider::HasCustomImage(int id) const {
if (!HasThemeableImage(id))
return false;
- if (theme_pack_)
- return theme_pack_->HasCustomImage(id);
-
- return false;
+ // A custom image = base name is NOT equal to resource name. See note in
+ // SaveThemeBitmap describing the process by which an original image is
+ // tagged.
+ ImageMap::const_iterator images_iter = images_.find(id);
+ ResourceNameMap::const_iterator names_iter = resource_names_.find(id);
+ if ((images_iter == images_.end()) || (names_iter == resource_names_.end()))
+ return false;
+ return !EndsWith(UTF8ToWide(images_iter->second),
+ UTF8ToWide(names_iter->second), false);
}
RefCountedMemory* BrowserThemeProvider::GetRawData(int id) const {
@@ -235,25 +458,57 @@ RefCountedMemory* BrowserThemeProvider::GetRawData(int id) const {
if (id == IDR_PRODUCT_LOGO && ntp_alternate != 0)
id = IDR_PRODUCT_LOGO_WHITE;
- RefCountedMemory* data = NULL;
- if (theme_pack_.get())
- data = theme_pack_->GetRawData(id);
+ RawDataMap::const_iterator data_iter = raw_data_.find(id);
+ if (data_iter != raw_data_.end())
+ return data_iter->second;
+
+ RefCountedMemory* data = ReadThemeFileData(id);
if (!data)
data = rb_.LoadDataResourceBytes(id);
+ if (!data)
+ return NULL;
+ raw_data_[id] = data;
return data;
}
void BrowserThemeProvider::SetTheme(Extension* extension) {
// Clear our image cache.
- FreePlatformCaches();
+ ClearCaches();
DCHECK(extension);
DCHECK(extension->IsTheme());
+ SetImageData(extension->GetThemeImages(),
+ extension->path());
+ SetColorData(extension->GetThemeColors());
+ SetTintData(extension->GetThemeTints());
+
+ // Drop out to default theme if the theme data is empty.
+ if (images_.empty() && colors_.empty() && tints_.empty()) {
+ UseDefaultTheme();
+ return;
+ }
+
+ SetDisplayPropertyData(extension->GetThemeDisplayProperties());
+ raw_data_.clear();
- BuildFromExtension(extension);
+ SaveImageData(extension->GetThemeImages());
+ SaveColorData();
+ SaveTintData();
+ SaveDisplayPropertyData();
SaveThemeID(extension->id());
+ // Process all images when we first set theme.
+ process_images_ = true;
+
+ GenerateFrameColors();
+ if (ShouldTintFrames()) {
+ AutoLock lock(themed_image_cache_lock_);
+ GenerateFrameImages();
+ GenerateTabImages();
+ }
+
+ WriteImagesToDisk();
NotifyThemeChanged();
UserMetrics::RecordAction("Themes_Installed", profile_);
}
@@ -288,6 +543,36 @@ std::string BrowserThemeProvider::GetThemeID() const {
return WideToUTF8(id);
}
+RefCountedMemory* BrowserThemeProvider::ReadThemeFileData(int id) const {
+ ImageMap::const_iterator images_iter = images_.find(id);
+ if (images_iter != images_.end()) {
+ // First check to see if we have a registered theme extension and whether
+ // it can handle this resource.
+#if defined(OS_WIN)
+ FilePath path = FilePath(UTF8ToWide(images_iter->second));
+#else
+ FilePath path = FilePath(images_iter->second);
+#endif
+ if (!path.empty()) {
+ net::FileStream file;
+ int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
+ if (file.Open(path, flags) == net::OK) {
+ int64 avail = file.Available();
+ if (avail > 0 && avail < INT_MAX) {
+ size_t size = static_cast<size_t>(avail);
+ std::vector<unsigned char> raw_data;
+ raw_data.resize(size);
+ char* data = reinterpret_cast<char*>(&(raw_data.front()));
+ if (file.ReadUntilComplete(data, size) == avail)
+ return RefCountedBytes::TakeVector(&raw_data);
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
// static
std::string BrowserThemeProvider::AlignmentToString(int alignment) {
// Convert from an AlignmentProperty back into a string.
@@ -361,8 +646,313 @@ int BrowserThemeProvider::StringToTiling(const std::string& tiling) {
return BrowserThemeProvider::NO_REPEAT;
}
-// static
-color_utils::HSL BrowserThemeProvider::GetDefaultTint(int id) {
+void BrowserThemeProvider::SetColor(const char* key, const SkColor& color) {
+ colors_[key] = color;
+}
+
+void BrowserThemeProvider::SetTint(const char* key,
+ const color_utils::HSL& tint) {
+ tints_[key] = tint;
+}
+
+color_utils::HSL BrowserThemeProvider::GetTint(int id) const {
+ DCHECK(CalledOnValidThread());
+
+ TintMap::const_iterator tint_iter = tints_.find(GetTintKey(id));
+ return (tint_iter == tints_.end()) ? GetDefaultTint(id) : tint_iter->second;
+}
+
+void BrowserThemeProvider::GenerateFrameColors() {
+ // Generate any secondary frame colors that weren't provided.
+ SkColor frame = GetColor(COLOR_FRAME);
+
+ if (!colors_.count(kColorFrame))
+ colors_[kColorFrame] = HSLShift(frame, GetTint(TINT_FRAME));
+ if (!colors_.count(kColorFrameInactive)) {
+ colors_[kColorFrameInactive] =
+ HSLShift(frame, GetTint(TINT_FRAME_INACTIVE));
+ }
+ if (!colors_.count(kColorFrameIncognito)) {
+ colors_[kColorFrameIncognito] =
+ HSLShift(frame, GetTint(TINT_FRAME_INCOGNITO));
+ }
+ if (!colors_.count(kColorFrameIncognitoInactive)) {
+ colors_[kColorFrameIncognitoInactive] =
+ HSLShift(frame, GetTint(TINT_FRAME_INCOGNITO_INACTIVE));
+ }
+}
+
+void BrowserThemeProvider::GenerateFrameImages() const {
+ // A map of frame image IDs to the tints for those ids.
+ typedef std::map<int, int> FrameTintMap;
+ static FrameTintMap frame_tints;
+ if (frame_tints.empty()) {
+ frame_tints[IDR_THEME_FRAME] = TINT_FRAME;
+ frame_tints[IDR_THEME_FRAME_INACTIVE] = TINT_FRAME_INACTIVE;
+ frame_tints[IDR_THEME_FRAME_OVERLAY] = TINT_FRAME;
+ frame_tints[IDR_THEME_FRAME_OVERLAY_INACTIVE] = TINT_FRAME_INACTIVE;
+ frame_tints[IDR_THEME_FRAME_INCOGNITO] = TINT_FRAME_INCOGNITO;
+ frame_tints[IDR_THEME_FRAME_INCOGNITO_INACTIVE] =
+ TINT_FRAME_INCOGNITO_INACTIVE;
+ }
+
+ for (FrameTintMap::const_iterator iter(frame_tints.begin());
+ iter != frame_tints.end(); ++iter) {
+ int id = iter->first;
+ scoped_ptr<SkBitmap> frame;
+ // If there's no frame image provided for the specified id, then load
+ // the default provided frame. If that's not provided, skip this whole
+ // thing and just use the default images.
+ int base_id;
+ std::string resource_name;
+
+ // If we've already processed the images for this theme, they're all
+ // waiting on disk -- just load them in.
+ if (!process_images_) {
+ frame.reset(LoadThemeBitmap(id));
+ if (frame.get())
+ themed_image_cache_[id] = new SkBitmap(*frame.get());
+ } else {
+ resource_name = resource_names_.find(id)->second;
+ if (id == IDR_THEME_FRAME_INCOGNITO_INACTIVE) {
+ base_id = HasCustomImage(IDR_THEME_FRAME_INCOGNITO) ?
+ IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME;
+ } else if (id == IDR_THEME_FRAME_OVERLAY_INACTIVE) {
+ base_id = IDR_THEME_FRAME_OVERLAY;
+ } else if (id == IDR_THEME_FRAME_INACTIVE) {
+ base_id = IDR_THEME_FRAME;
+ } else if (id == IDR_THEME_FRAME_INCOGNITO &&
+ !HasCustomImage(IDR_THEME_FRAME_INCOGNITO)) {
+ base_id = IDR_THEME_FRAME;
+ } else {
+ base_id = id;
+ }
+
+ if (HasCustomImage(id)) {
+ frame.reset(LoadThemeBitmap(id));
+ } else if (base_id != id && HasCustomImage(base_id)) {
+ frame.reset(LoadThemeBitmap(base_id));
+ } else if (base_id == IDR_THEME_FRAME_OVERLAY &&
+ HasCustomImage(IDR_THEME_FRAME)) {
+ // If there is no theme overlay, don't tint the default frame,
+ // because it will overwrite the custom frame image when we cache and
+ // reload from disk.
+ frame.reset(NULL);
+ } else {
+ // If the theme doesn't specify an image, then apply the tint to
+ // the default frame.
+ frame.reset(new SkBitmap(*rb_.GetBitmapNamed(IDR_THEME_FRAME)));
+ }
+
+ if (frame.get()) {
+ SkBitmap* tinted = new SkBitmap(TintBitmap(*frame, iter->second));
+ themed_image_cache_[id] = tinted;
+ SaveThemeBitmap(resource_name, id);
+ }
+ }
+ }
+}
+
+void BrowserThemeProvider::GenerateTabImages() const {
+ GenerateTabBackgroundBitmap(IDR_THEME_TAB_BACKGROUND);
+ GenerateTabBackgroundBitmap(IDR_THEME_TAB_BACKGROUND_INCOGNITO);
+}
+
+void BrowserThemeProvider::ClearAllThemeData() {
+ // Clear our image cache.
+ ClearCaches();
+
+ images_.clear();
+ colors_.clear();
+ tints_.clear();
+ display_properties_.clear();
+ raw_data_.clear();
+
+ SaveImageData(NULL);
+ SaveColorData();
+ SaveTintData();
+ SaveDisplayPropertyData();
+ SaveThemeID(kDefaultThemeID);
+}
+
+void BrowserThemeProvider::LoadThemePrefs() {
+ process_images_ = false;
+ PrefService* prefs = profile_->GetPrefs();
+
+ // TODO(glen): Figure out if any custom prefs were loaded, and if so UMA-log
+ // the fact that a theme was loaded.
+ if (!prefs->HasPrefPath(prefs::kCurrentThemeImages) &&
+ !prefs->HasPrefPath(prefs::kCurrentThemeColors) &&
+ !prefs->HasPrefPath(prefs::kCurrentThemeTints))
+ return;
+
+ // Our prefs already have the extension path baked in, so we don't need to
+ // provide it.
+ SetImageData(prefs->GetMutableDictionary(prefs::kCurrentThemeImages),
+ FilePath());
+ SetColorData(prefs->GetMutableDictionary(prefs::kCurrentThemeColors));
+ SetTintData(prefs->GetMutableDictionary(prefs::kCurrentThemeTints));
+ SetDisplayPropertyData(
+ prefs->GetMutableDictionary(prefs::kCurrentThemeDisplayProperties));
+
+ // If we're not loading the frame from the cached image dir, we are using an
+ // old preferences file, or the processed images were not saved correctly.
+ // Force image reprocessing and caching.
+ ImageMap::const_iterator images_iter = images_.find(IDR_THEME_FRAME);
+ if (images_iter != images_.end()) {
+#if defined(OS_WIN)
+ FilePath cache_path = FilePath(UTF8ToWide(images_iter->second));
+#else
+ FilePath cache_path = FilePath(images_iter->second);
+#endif
+ process_images_ = !file_util::ContainsPath(image_dir_, cache_path);
+ }
+
+ GenerateFrameColors();
+ // Scope for AutoLock on themed_image_cache.
+ {
+ AutoLock lock(themed_image_cache_lock_);
+ GenerateFrameImages();
+ GenerateTabImages();
+ }
+
+ if (process_images_) {
+ WriteImagesToDisk();
+ UserMetrics::RecordAction("Migrated noncached to cached theme.", profile_);
+ }
+ UserMetrics::RecordAction("Themes_loaded", profile_);
+}
+
+void BrowserThemeProvider::NotifyThemeChanged() {
+ // Redraw!
+ NotificationService* service = NotificationService::current();
+ service->Notify(NotificationType::BROWSER_THEME_CHANGED,
+ Source<BrowserThemeProvider>(this),
+ NotificationService::NoDetails());
+}
+
+SkBitmap* BrowserThemeProvider::LoadThemeBitmap(int id) const {
+ DCHECK(CalledOnValidThread());
+
+ if (!HasThemeableImage(id))
+ return NULL;
+
+ scoped_refptr<RefCountedMemory> raw_data;
+
+ // We special case images related to the NTP so we first try raw data. Why?
+ // Because the DOMUI stuff uses that interface to return raw PNG data instead
+ // of the normal theme interface which returns SkBitmaps. GetRawData() also
+ // caches the PNG data so it opens new tab pages faster. If we didn't try and
+ // otherwise we would be loading big images twice, once through GetRawData()
+ // and once here. Ouch. So either we prime the GetRawData() cache for when
+ // DOMUIThemeSource requests our image, or we take advantage of the already
+ // loaded data, saving a trip to disk.
+ if (id == IDR_THEME_NTP_BACKGROUND)
+ raw_data = GetRawData(id);
+
+ if (!raw_data)
+ raw_data = ReadThemeFileData(id);
+
+ if (raw_data) {
+ // Decode the PNG.
+ SkBitmap bitmap;
+ if (!gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(),
+ &bitmap)) {
+ NOTREACHED() << "Unable to decode theme image resource " << id;
+ return NULL;
+ }
+
+ return new SkBitmap(bitmap);
+ } else {
+ // TODO(glen): File no-longer exists, we're out of date. We should
+ // clear the theme (or maybe just the pref that points to this
+ // image).
+ return NULL;
+ }
+}
+
+void BrowserThemeProvider::SaveThemeBitmap(std::string resource_name,
+ int id) const {
+ DCHECK(CalledOnValidThread());
+ if (!themed_image_cache_.count(id)) {
+ NOTREACHED();
+ return;
+ }
+
+ // The images_ directory, at this point, contains only the custom images
+ // provided by the extension. We tag these images "_original" in the prefs
+ // file so we can distinguish them from images which have been generated and
+ // saved to disk by the theme caching process (WriteImagesToDisk). This way,
+ // when we call HasCustomImage, we can check for the "_original" tag to see
+ // whether an image was originally provided by the extension, or saved
+ // in the caching process.
+ if (images_.count(id))
+ resource_name.append("_original");
+
+#if defined(OS_WIN)
+ FilePath image_path = image_dir_.Append(UTF8ToWide(resource_name));
+#elif defined(OS_POSIX)
+ FilePath image_path = image_dir_.Append(resource_name);
+#endif
+
+ images_disk_cache_[image_path] = id;
+}
+
+#if defined(OS_WIN)
+void BrowserThemeProvider::FreePlatformCaches() {
+ // Views (Skia) has no platform image cache to clear.
+}
+#endif
+
+SkBitmap* BrowserThemeProvider::GenerateTabBackgroundBitmapImpl(int id) const {
+ int base_id = (id == IDR_THEME_TAB_BACKGROUND) ?
+ IDR_THEME_FRAME : IDR_THEME_FRAME_INCOGNITO;
+ // According to Miranda, it is safe to read from the themed_image_cache_ here
+ // because we only lock to write on the UI thread, and we only lock to read
+ // on the cache writing thread.
+ ImageCache::const_iterator themed_iter = themed_image_cache_.find(base_id);
+ if (themed_iter == themed_image_cache_.end())
+ return NULL;
+
+ SkBitmap bg_tint = TintBitmap(*(themed_iter->second), TINT_BACKGROUND_TAB);
+ int vertical_offset = HasCustomImage(id) ? kRestoredTabVerticalOffset : 0;
+ SkBitmap* bg_tab = new SkBitmap(SkBitmapOperations::CreateTiledBitmap(
+ bg_tint, 0, vertical_offset, bg_tint.width(), bg_tint.height()));
+
+ // If they've provided a custom image, overlay it.
+ if (HasCustomImage(id)) {
+ SkBitmap* overlay = LoadThemeBitmap(id);
+ if (overlay) {
+ SkCanvas canvas(*bg_tab);
+ for (int x = 0; x < bg_tab->width(); x += overlay->width())
+ canvas.drawBitmap(*overlay, static_cast<SkScalar>(x), 0, NULL);
+ }
+ }
+
+ return bg_tab;
+}
+
+const std::string BrowserThemeProvider::GetTintKey(int id) const {
+ switch (id) {
+ case TINT_FRAME:
+ return kTintFrame;
+ case TINT_FRAME_INACTIVE:
+ return kTintFrameInactive;
+ case TINT_FRAME_INCOGNITO:
+ return kTintFrameIncognito;
+ case TINT_FRAME_INCOGNITO_INACTIVE:
+ return kTintFrameIncognitoInactive;
+ case TINT_BUTTONS:
+ return kTintButtons;
+ case TINT_BACKGROUND_TAB:
+ return kTintBackgroundTab;
+ default:
+ NOTREACHED() << "Unknown tint requested";
+ return "";
+ }
+}
+
+color_utils::HSL BrowserThemeProvider::GetDefaultTint(int id) const {
switch (id) {
case TINT_FRAME:
return kDefaultTintFrame;
@@ -382,8 +972,53 @@ color_utils::HSL BrowserThemeProvider::GetDefaultTint(int id) {
}
}
-// static
-SkColor BrowserThemeProvider::GetDefaultColor(int id) {
+const std::string BrowserThemeProvider::GetColorKey(int id) const {
+ switch (id) {
+ case COLOR_FRAME:
+ return kColorFrame;
+ case COLOR_FRAME_INACTIVE:
+ return kColorFrameInactive;
+ case COLOR_FRAME_INCOGNITO:
+ return kColorFrameIncognito;
+ case COLOR_FRAME_INCOGNITO_INACTIVE:
+ return kColorFrameIncognitoInactive;
+ case COLOR_TOOLBAR:
+ return kColorToolbar;
+ case COLOR_TAB_TEXT:
+ return kColorTabText;
+ case COLOR_BACKGROUND_TAB_TEXT:
+ return kColorBackgroundTabText;
+ case COLOR_BOOKMARK_TEXT:
+ return kColorBookmarkText;
+ case COLOR_NTP_BACKGROUND:
+ return kColorNTPBackground;
+ case COLOR_NTP_TEXT:
+ return kColorNTPText;
+ case COLOR_NTP_LINK:
+ return kColorNTPLink;
+ case COLOR_NTP_LINK_UNDERLINE:
+ return kColorNTPLinkUnderline;
+ case COLOR_NTP_HEADER:
+ return kColorNTPHeader;
+ case COLOR_NTP_SECTION:
+ return kColorNTPSection;
+ case COLOR_NTP_SECTION_TEXT:
+ return kColorNTPSectionText;
+ case COLOR_NTP_SECTION_LINK:
+ return kColorNTPSectionLink;
+ case COLOR_NTP_SECTION_LINK_UNDERLINE:
+ return kColorNTPSectionLinkUnderline;
+ case COLOR_CONTROL_BACKGROUND:
+ return kColorControlBackground;
+ case COLOR_BUTTON_BACKGROUND:
+ return kColorButtonBackground;
+ default:
+ NOTREACHED() << "Unknown color requested";
+ return "";
+ }
+}
+
+SkColor BrowserThemeProvider::GetDefaultColor(int id) const {
switch (id) {
case COLOR_FRAME:
return kDefaultColorFrame;
@@ -407,8 +1042,6 @@ SkColor BrowserThemeProvider::GetDefaultColor(int id) {
return kDefaultColorNTPText;
case COLOR_NTP_LINK:
return kDefaultColorNTPLink;
- case COLOR_NTP_LINK_UNDERLINE:
- return TintForUnderline(kDefaultColorNTPLink);
case COLOR_NTP_HEADER:
return kDefaultColorNTPHeader;
case COLOR_NTP_SECTION:
@@ -417,8 +1050,6 @@ SkColor BrowserThemeProvider::GetDefaultColor(int id) {
return kDefaultColorNTPSectionText;
case COLOR_NTP_SECTION_LINK:
return kDefaultColorNTPSectionLink;
- case COLOR_NTP_SECTION_LINK_UNDERLINE:
- return TintForUnderline(kDefaultColorNTPSectionLink);
case COLOR_CONTROL_BACKGROUND:
return kDefaultColorControlBackground;
case COLOR_BUTTON_BACKGROUND:
@@ -429,97 +1060,289 @@ SkColor BrowserThemeProvider::GetDefaultColor(int id) {
}
}
-color_utils::HSL BrowserThemeProvider::GetTint(int id) const {
- DCHECK(CalledOnValidThread());
+SkBitmap BrowserThemeProvider::TintBitmap(const SkBitmap& bitmap,
+ int hsl_id) const {
+ return SkBitmapOperations::CreateHSLShiftedBitmap(bitmap, GetTint(hsl_id));
+}
+
+void BrowserThemeProvider::SetImageData(DictionaryValue* images_value,
+ FilePath images_path) {
+ images_.clear();
- color_utils::HSL hsl;
- if (theme_pack_.get() && theme_pack_->GetTint(id, &hsl))
- return hsl;
+ if (!images_value)
+ return;
- return GetDefaultTint(id);
+ for (DictionaryValue::key_iterator iter(images_value->begin_keys());
+ iter != images_value->end_keys(); ++iter) {
+ std::string val;
+ if (images_value->GetStringWithoutPathExpansion(*iter, &val)) {
+ int id = ThemeResourcesUtil::GetId(WideToUTF8(*iter));
+ if (id != -1) {
+ if (!images_path.empty()) {
+ images_[id] =
+ WideToUTF8(images_path.AppendASCII(val).ToWStringHack());
+ resource_names_[id] = WideToASCII(*iter);
+ } else {
+ images_[id] = val;
+ }
+ }
+ }
+ }
}
-void BrowserThemeProvider::ClearAllThemeData() {
- // Clear our image cache.
- FreePlatformCaches();
- theme_pack_ = NULL;
+void BrowserThemeProvider::SetColorData(DictionaryValue* colors_value) {
+ colors_.clear();
- profile_->GetPrefs()->ClearPref(prefs::kCurrentThemePackFilename);
- SaveThemeID(kDefaultThemeID);
+ if (!colors_value)
+ return;
+
+ for (DictionaryValue::key_iterator iter(colors_value->begin_keys());
+ iter != colors_value->end_keys(); ++iter) {
+ ListValue* color_list;
+ if (colors_value->GetListWithoutPathExpansion(*iter, &color_list) &&
+ ((color_list->GetSize() == 3) || (color_list->GetSize() == 4))) {
+ int r, g, b;
+ color_list->GetInteger(0, &r);
+ color_list->GetInteger(1, &g);
+ color_list->GetInteger(2, &b);
+ if (color_list->GetSize() == 4) {
+ double alpha;
+ int alpha_int;
+ if (color_list->GetReal(3, &alpha)) {
+ colors_[WideToUTF8(*iter)] =
+ SkColorSetARGB(static_cast<int>(alpha * 255), r, g, b);
+ } else if (color_list->GetInteger(3, &alpha_int) &&
+ (alpha_int == 0 || alpha_int == 1)) {
+ colors_[WideToUTF8(*iter)] =
+ SkColorSetARGB(alpha_int ? 255 : 0, r, g, b);
+ }
+ } else {
+ colors_[WideToUTF8(*iter)] = SkColorSetRGB(r, g, b);
+ }
+ }
+ }
}
-void BrowserThemeProvider::LoadThemePrefs() {
- PrefService* prefs = profile_->GetPrefs();
+void BrowserThemeProvider::SetTintData(DictionaryValue* tints_value) {
+ tints_.clear();
- std::string current_id = GetThemeID();
- if (current_id != kDefaultThemeID) {
- bool loaded_pack = false;
+ if (!tints_value)
+ return;
- // If we don't have a file pack, we're updating from an old version.
- FilePath path = prefs->GetFilePath(prefs::kCurrentThemePackFilename);
- if (path != FilePath()) {
- theme_pack_ = BrowserThemePack::BuildFromDataPack(path, current_id);
- loaded_pack = theme_pack_.get() != NULL;
+ for (DictionaryValue::key_iterator iter(tints_value->begin_keys());
+ iter != tints_value->end_keys(); ++iter) {
+ ListValue* tint_list;
+ if (tints_value->GetListWithoutPathExpansion(*iter, &tint_list) &&
+ (tint_list->GetSize() == 3)) {
+ color_utils::HSL hsl = { -1, -1, -1 };
+ int value = 0;
+ if (!tint_list->GetReal(0, &hsl.h) && tint_list->GetInteger(0, &value))
+ hsl.h = value;
+ if (!tint_list->GetReal(1, &hsl.s) && tint_list->GetInteger(1, &value))
+ hsl.s = value;
+ if (!tint_list->GetReal(2, &hsl.l) && tint_list->GetInteger(2, &value))
+ hsl.l = value;
+
+ tints_[WideToUTF8(*iter)] = hsl;
}
+ }
+}
- if (loaded_pack) {
- UserMetrics::RecordAction("Themes.Loaded", profile_);
+void BrowserThemeProvider::SetDisplayPropertyData(
+ DictionaryValue* display_properties_value) {
+ display_properties_.clear();
+
+ if (!display_properties_value)
+ return;
+
+ for (DictionaryValue::key_iterator iter(
+ display_properties_value->begin_keys());
+ iter != display_properties_value->end_keys(); ++iter) {
+ // New tab page alignment and background tiling.
+ if (base::strcasecmp(WideToUTF8(*iter).c_str(),
+ kDisplayPropertyNTPAlignment) == 0) {
+ std::string val;
+ if (display_properties_value->GetStringWithoutPathExpansion(*iter,
+ &val)) {
+ display_properties_[kDisplayPropertyNTPAlignment] =
+ StringToAlignment(val);
+ }
+ } else if (base::strcasecmp(WideToUTF8(*iter).c_str(),
+ kDisplayPropertyNTPTiling) == 0) {
+ std::string val;
+ if (display_properties_value->GetStringWithoutPathExpansion(*iter, &val))
+ display_properties_[kDisplayPropertyNTPTiling] = StringToTiling(val);
+ }
+ if (base::strcasecmp(WideToUTF8(*iter).c_str(),
+ kDisplayPropertyNTPInverseLogo) == 0) {
+ int val = 0;
+ if (display_properties_value->GetIntegerWithoutPathExpansion(*iter, &val))
+ display_properties_[kDisplayPropertyNTPInverseLogo] = val;
+ }
+ }
+}
+
+SkBitmap* BrowserThemeProvider::GenerateTabBackgroundBitmap(int id) const {
+ if (id == IDR_THEME_TAB_BACKGROUND ||
+ id == IDR_THEME_TAB_BACKGROUND_INCOGNITO) {
+ // The requested image is a background tab. Get a frame to create the
+ // tab against. As themes don't use the glass frame, we don't have to
+ // worry about compositing them together, as our default theme provides
+ // the necessary bitmaps.
+ if (!process_images_) {
+ scoped_ptr<SkBitmap> frame;
+ frame.reset(LoadThemeBitmap(id));
+ if (frame.get())
+ themed_image_cache_[id] = new SkBitmap(*frame.get());
} else {
- // TODO(erg): We need to pop up a dialog informing the user that their
- // theme is being migrated.
- ExtensionsService* service = profile_->GetExtensionsService();
- if (service) {
- Extension* extension = service->GetExtensionById(current_id, false);
- if (extension) {
- DLOG(ERROR) << "Migrating theme";
- BuildFromExtension(extension);
- UserMetrics::RecordAction("Themes.Migrated", profile_);
- } else {
- DLOG(ERROR) << "Theme is mysteriously gone.";
- ClearAllThemeData();
- UserMetrics::RecordAction("Themes.Gone", profile_);
- }
+ SkBitmap* bg_tab = GenerateTabBackgroundBitmapImpl(id);
+
+ if (bg_tab) {
+ std::string resource_name((id == IDR_THEME_TAB_BACKGROUND) ?
+ "theme_tab_background" : "theme_tab_background_incognito");
+ themed_image_cache_[id] = bg_tab;
+ SaveThemeBitmap(resource_name, id);
+ return bg_tab;
}
}
}
+ return NULL;
}
-void BrowserThemeProvider::NotifyThemeChanged() {
- // Redraw!
- NotificationService* service = NotificationService::current();
- service->Notify(NotificationType::BROWSER_THEME_CHANGED,
- Source<BrowserThemeProvider>(this),
- NotificationService::NoDetails());
+void BrowserThemeProvider::SaveImageData(DictionaryValue* images_value) const {
+ // Save our images data.
+ DictionaryValue* pref_images =
+ profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeImages);
+ pref_images->Clear();
+
+ if (!images_value)
+ return;
+
+ for (DictionaryValue::key_iterator iter(images_value->begin_keys());
+ iter != images_value->end_keys(); ++iter) {
+ std::string val;
+ if (images_value->GetStringWithoutPathExpansion(*iter, &val)) {
+ int id = ThemeResourcesUtil::GetId(WideToUTF8(*iter));
+ if (id != -1) {
+ pref_images->SetWithoutPathExpansion(*iter,
+ Value::CreateStringValue(images_.find(id)->second));
+ }
+ }
+ }
}
-#if defined(OS_WIN)
-void BrowserThemeProvider::FreePlatformCaches() {
- // Views (Skia) has no platform image cache to clear.
+void BrowserThemeProvider::SaveColorData() const {
+ // Save our color data.
+ DictionaryValue* pref_colors =
+ profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeColors);
+ pref_colors->Clear();
+
+ if (colors_.empty())
+ return;
+
+ for (ColorMap::const_iterator iter(colors_.begin()); iter != colors_.end();
+ ++iter) {
+ SkColor rgba = iter->second;
+ ListValue* rgb_list = new ListValue();
+ rgb_list->Set(0, Value::CreateIntegerValue(SkColorGetR(rgba)));
+ rgb_list->Set(1, Value::CreateIntegerValue(SkColorGetG(rgba)));
+ rgb_list->Set(2, Value::CreateIntegerValue(SkColorGetB(rgba)));
+ if (SkColorGetA(rgba) != 255)
+ rgb_list->Set(3, Value::CreateRealValue(SkColorGetA(rgba) / 255.0));
+ pref_colors->Set(UTF8ToWide(iter->first), rgb_list);
+ }
}
-#endif
-void BrowserThemeProvider::SavePackName(const FilePath& pack_path) {
- profile_->GetPrefs()->SetFilePath(
- prefs::kCurrentThemePackFilename, pack_path);
+void BrowserThemeProvider::SaveTintData() const {
+ // Save our tint data.
+ DictionaryValue* pref_tints =
+ profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeTints);
+ pref_tints->Clear();
+
+ if (tints_.empty())
+ return;
+
+ for (TintMap::const_iterator iter(tints_.begin()); iter != tints_.end();
+ ++iter) {
+ color_utils::HSL hsl = iter->second;
+ ListValue* hsl_list = new ListValue();
+ hsl_list->Set(0, Value::CreateRealValue(hsl.h));
+ hsl_list->Set(1, Value::CreateRealValue(hsl.s));
+ hsl_list->Set(2, Value::CreateRealValue(hsl.l));
+ pref_tints->Set(UTF8ToWide(iter->first), hsl_list);
+ }
+}
+
+void BrowserThemeProvider::SaveDisplayPropertyData() const {
+ // Save our display property data.
+ DictionaryValue* pref_display_properties =
+ profile_->GetPrefs()->
+ GetMutableDictionary(prefs::kCurrentThemeDisplayProperties);
+ pref_display_properties->Clear();
+
+ if (display_properties_.empty())
+ return;
+
+ for (DisplayPropertyMap::const_iterator iter(display_properties_.begin());
+ iter != display_properties_.end(); ++iter) {
+ if (base::strcasecmp(iter->first.c_str(),
+ kDisplayPropertyNTPAlignment) == 0) {
+ pref_display_properties->SetString(UTF8ToWide(iter->first),
+ AlignmentToString(iter->second));
+ } else if (base::strcasecmp(iter->first.c_str(),
+ kDisplayPropertyNTPTiling) == 0) {
+ pref_display_properties->SetString(UTF8ToWide(iter->first),
+ TilingToString(iter->second));
+ }
+ if (base::strcasecmp(iter->first.c_str(),
+ kDisplayPropertyNTPInverseLogo) == 0) {
+ pref_display_properties->SetInteger(UTF8ToWide(iter->first),
+ iter->second);
+ }
+ }
+}
+
+void BrowserThemeProvider::SaveCachedImageData() const {
+ DictionaryValue* pref_images =
+ profile_->GetPrefs()->GetMutableDictionary(prefs::kCurrentThemeImages);
+
+ for (ImagesDiskCache::const_iterator it(images_disk_cache_.begin());
+ it != images_disk_cache_.end(); ++it) {
+ std::wstring disk_path = it->first.ToWStringHack();
+ std::string pref_name = resource_names_.find(it->second)->second;
+ pref_images->SetString(UTF8ToWide(pref_name), WideToUTF8(disk_path));
+ }
+ profile_->GetPrefs()->ScheduleSavePersistentPrefs();
}
void BrowserThemeProvider::SaveThemeID(const std::string& id) {
profile_->GetPrefs()->SetString(prefs::kCurrentThemeID, UTF8ToWide(id));
}
-void BrowserThemeProvider::BuildFromExtension(Extension* extension) {
- scoped_refptr<BrowserThemePack> pack =
- BrowserThemePack::BuildFromExtension(extension);
- if (!pack.get()) {
- NOTREACHED() << "Could not load theme.";
- return;
+void BrowserThemeProvider::ClearCaches() {
+ FreePlatformCaches();
+ STLDeleteValues(&image_cache_);
+
+ // Scope for AutoLock on themed_image_cache.
+ {
+ AutoLock lock(themed_image_cache_lock_);
+ STLDeleteValues(&themed_image_cache_);
}
- // Write the packed file to disk.
- FilePath pack_path = extension->path().Append(chrome::kThemePackFilename);
- ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
- new WritePackToDiskTask(pack, pack_path));
+ images_disk_cache_.clear();
+}
+
+void BrowserThemeProvider::WriteImagesToDisk() const {
+ g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
+ new WriteImagesToDiskTask(images_disk_cache_, themed_image_cache_));
+ SaveCachedImageData();
+}
- SavePackName(pack_path);
- theme_pack_ = pack;
+bool BrowserThemeProvider::ShouldTintFrames() const {
+ return (HasCustomImage(IDR_THEME_FRAME) ||
+ tints_.count(GetTintKey(TINT_BACKGROUND_TAB)) ||
+ tints_.count(GetTintKey(TINT_FRAME)) ||
+ tints_.count(GetTintKey(TINT_FRAME_INACTIVE)) ||
+ tints_.count(GetTintKey(TINT_FRAME_INCOGNITO)) ||
+ tints_.count(GetTintKey(TINT_FRAME_INCOGNITO_INACTIVE)));
}
diff --git a/chrome/browser/browser_theme_provider.h b/chrome/browser/browser_theme_provider.h
index a06d7ee..04117b4 100644
--- a/chrome/browser/browser_theme_provider.h
+++ b/chrome/browser/browser_theme_provider.h
@@ -22,13 +22,48 @@ class Profile;
class DictionaryValue;
class PrefService;
class BrowserThemeProviderTest;
-class BrowserThemePack;
class BrowserThemeProvider : public NonThreadSafe,
public ThemeProvider {
public:
// Public constants used in BrowserThemeProvider and its subclasses:
+ // Strings used by themes to identify colors for different parts of our UI.
+ static const char* kColorFrame;
+ static const char* kColorFrameInactive;
+ static const char* kColorFrameIncognito;
+ static const char* kColorFrameIncognitoInactive;
+ static const char* kColorToolbar;
+ static const char* kColorTabText;
+ static const char* kColorBackgroundTabText;
+ static const char* kColorBookmarkText;
+ static const char* kColorNTPBackground;
+ static const char* kColorNTPText;
+ static const char* kColorNTPLink;
+ static const char* kColorNTPLinkUnderline;
+ static const char* kColorNTPHeader;
+ static const char* kColorNTPSection;
+ static const char* kColorNTPSectionText;
+ static const char* kColorNTPSectionLink;
+ static const char* kColorNTPSectionLinkUnderline;
+ static const char* kColorControlBackground;
+ static const char* kColorButtonBackground;
+
+ // Strings used by themes to identify tints to apply to different parts of
+ // our UI. The frame tints apply to the frame color and produce the
+ // COLOR_FRAME* colors.
+ static const char* kTintButtons;
+ static const char* kTintFrame;
+ static const char* kTintFrameInactive;
+ static const char* kTintFrameIncognito;
+ static const char* kTintFrameIncognitoInactive;
+ static const char* kTintBackgroundTab;
+
+ // Strings used by themes to identify miscellaneous numerical properties.
+ static const char* kDisplayPropertyNTPAlignment;
+ static const char* kDisplayPropertyNTPTiling;
+ static const char* kDisplayPropertyNTPInverseLogo;
+
// Strings used in alignment properties.
static const char* kAlignmentTop;
static const char* kAlignmentBottom;
@@ -41,11 +76,38 @@ class BrowserThemeProvider : public NonThreadSafe,
static const char* kTilingRepeatY;
static const char* kTilingRepeat;
+ // Default colors.
+ static const SkColor kDefaultColorFrame;
+ static const SkColor kDefaultColorFrameInactive;
+ static const SkColor kDefaultColorFrameIncognito;
+ static const SkColor kDefaultColorFrameIncognitoInactive;
+ static const SkColor kDefaultColorToolbar;
+ static const SkColor kDefaultColorTabText;
+ static const SkColor kDefaultColorBackgroundTabText;
+ static const SkColor kDefaultColorBookmarkText;
+ static const SkColor kDefaultColorNTPBackground;
+ static const SkColor kDefaultColorNTPText;
+ static const SkColor kDefaultColorNTPLink;
+ static const SkColor kDefaultColorNTPHeader;
+ static const SkColor kDefaultColorNTPSection;
+ static const SkColor kDefaultColorNTPSectionText;
+ static const SkColor kDefaultColorNTPSectionLink;
+ static const SkColor kDefaultColorControlBackground;
+ static const SkColor kDefaultColorButtonBackground;
+
+ static const color_utils::HSL kDefaultTintButtons;
+ static const color_utils::HSL kDefaultTintFrame;
+ static const color_utils::HSL kDefaultTintFrameInactive;
+ static const color_utils::HSL kDefaultTintFrameIncognito;
+ static const color_utils::HSL kDefaultTintFrameIncognitoInactive;
+ static const color_utils::HSL kDefaultTintBackgroundTab;
+
static const char* kDefaultThemeID;
// Returns true if the image is themeable. Safe to call on any thread.
static bool IsThemeableImage(int resource_id);
+
BrowserThemeProvider();
virtual ~BrowserThemeProvider();
@@ -128,6 +190,10 @@ class BrowserThemeProvider : public NonThreadSafe,
// locally customized.)
std::string GetThemeID() const;
+ // Reads the image data from the theme file into the specified vector. Returns
+ // true on success.
+ RefCountedMemory* ReadThemeFileData(int id) const;
+
// Convert a bitfield alignment into a string like "top left". Public so that
// it can be used to generate CSS values. Takes a bitfield of AlignmentMasks.
static std::string AlignmentToString(int alignment);
@@ -143,21 +209,44 @@ class BrowserThemeProvider : public NonThreadSafe,
// Parse tiling values from something like "no-repeat" into a Tiling value.
static int StringToTiling(const std::string& tiling);
- // Returns the default tint for the given tint |id| TINT_* enum value.
- static color_utils::HSL GetDefaultTint(int id);
-
- // Returns the default color for the given color |id| COLOR_* enum value.
- static SkColor GetDefaultColor(int id);
+ // Lock on write to themed_image_cache_ in UI thread; lock on all cache
+ // access in File thread. This allows the File thread and UI thread to
+ // both read themed images at the same time, while preventing simultaneous
+ // File thread read and UI thread write.
+ static Lock themed_image_cache_lock_;
// Save the images to be written to disk, mapping file path to id.
typedef std::map<FilePath, int> ImagesDiskCache;
+ // Cached images. We cache all retrieved and generated bitmaps and keep
+ // track of the pointers. We own these and will delete them when we're done
+ // using them.
+ typedef std::map<int, SkBitmap*> ImageCache;
+
protected:
+ // Sets an individual color value.
+ void SetColor(const char* id, const SkColor& color);
+
+ // Sets an individual tint value.
+ void SetTint(const char* id, const color_utils::HSL& tint);
+
// Get the specified tint - |id| is one of the TINT_* enum values.
color_utils::HSL GetTint(int id) const;
+ // Generate any frame colors that weren't specified.
+ void GenerateFrameColors();
+
+ // Generate any frame images that weren't specified. The resulting images
+ // will be stored in our cache and written to disk. If images have already
+ // been generated and cached, load them from disk.
+ void GenerateFrameImages() const;
+
+ // Generate any tab images that weren't specified. The resulting images
+ // will be stored in our cache.
+ void GenerateTabImages() const;
+
// Clears all the override fields and saves the dictionary.
- virtual void ClearAllThemeData();
+ void ClearAllThemeData();
// Load theme data from preferences.
virtual void LoadThemePrefs();
@@ -165,33 +254,116 @@ class BrowserThemeProvider : public NonThreadSafe,
// Let all the browser views know that themes have changed.
virtual void NotifyThemeChanged();
+ // Loads a bitmap from the theme, which may be tinted or
+ // otherwise modified, or an application default.
+ virtual SkBitmap* LoadThemeBitmap(int id) const;
+
+ // Save the modified bitmap at image_cache_[id].
+ virtual void SaveThemeBitmap(std::string resource_name, int id) const;
+
// Clears the platform-specific caches. Do not call directly; it's called
// from ClearCaches().
virtual void FreePlatformCaches();
+ // The implementation of GenerateTabBackgroundBitmap(). That function also
+ // must be locked and touches caches; this function only deals with image
+ // generation.
+ SkBitmap* GenerateTabBackgroundBitmapImpl(int id) const;
+
Profile* profile() { return profile_; }
+ // Subclasses may need us to not use the on-disk image cache. The GTK
+ // interface needs to generate some images itself.
+ void force_process_images() { process_images_ = true; }
+
private:
friend class BrowserThemeProviderTest;
- // Saves the filename of the cached theme pack.
- void SavePackName(const FilePath& pack_path);
+ typedef std::map<const int, std::string> ImageMap;
+ typedef std::map<const std::string, SkColor> ColorMap;
+ typedef std::map<const std::string, color_utils::HSL> TintMap;
+ typedef std::map<const std::string, int> DisplayPropertyMap;
+ typedef std::map<const int, scoped_refptr<RefCountedMemory> > RawDataMap;
+ typedef std::map<const int, std::string> ResourceNameMap;
+
+ // Returns the string key for the given tint |id| TINT_* enum value.
+ const std::string GetTintKey(int id) const;
+
+ // Returns the default tint for the given tint |id| TINT_* enum value.
+ color_utils::HSL GetDefaultTint(int id) const;
+
+ // Returns the string key for the given color |id| COLOR_* enum value.
+ const std::string GetColorKey(int id) const;
+
+ // Returns the default color for the given color |id| COLOR_* enum value.
+ SkColor GetDefaultColor(int id) const;
+
+ // Tint |bitmap| with the tint specified by |hsl_id|
+ SkBitmap TintBitmap(const SkBitmap& bitmap, int hsl_id) const;
+
+ // The following load data from specified dictionaries (either from
+ // preferences or from an extension manifest) and update our theme
+ // data appropriately.
+ // Allow any ResourceBundle image to be overridden. |images| should
+ // contain keys defined in ThemeResourceMap, and values as paths to
+ // the images on-disk.
+ void SetImageData(DictionaryValue* images, FilePath images_path);
+
+ // Set our theme colors. The keys of |colors| are any of the kColor*
+ // constants, and the values are a three-item list containing 8-bit
+ // RGB values.
+ void SetColorData(DictionaryValue* colors);
+
+ // Set tint data for our images and colors. The keys of |tints| are
+ // any of the kTint* contstants, and the values are a three-item list
+ // containing real numbers in the range 0-1 (and -1 for 'null').
+ void SetTintData(DictionaryValue* tints);
+
+ // Set miscellaneous display properties. While these can be defined as
+ // strings, they are currently stored as integers.
+ void SetDisplayPropertyData(DictionaryValue* display_properties);
+
+ // Create any images that aren't pregenerated (e.g. background tab images).
+ SkBitmap* GenerateTabBackgroundBitmap(int id) const;
+
+ // Save our data - when saving images we need the original dictionary
+ // from the extension because it contains the text ids that we want to save.
+ void SaveImageData(DictionaryValue* images) const;
+ void SaveColorData() const;
+ void SaveTintData() const;
+ void SaveDisplayPropertyData() const;
+
+ // Save the paths of data we have written to disk in prefs.
+ void SaveCachedImageData() const;
// Save the id of the last theme installed.
void SaveThemeID(const std::string& id);
- // Implementation of SetTheme() (and the fallback from LoadThemePrefs() in
- // case we don't have a theme pack).
- void BuildFromExtension(Extension* extension);
+ // Frees generated images and clears the image cache.
+ void ClearCaches();
// Remove preference values for themes that are no longer in use.
void RemoveUnusedThemes();
+ // Encode image at image_cache_[id] as PNG and write to disk.
+ void WriteImagesToDisk() const;
+
+ // Do we have a custom frame image or custom tints?
+ bool ShouldTintFrames() const;
+
#if defined(OS_LINUX)
// Loads an image and flips it horizontally if |rtl_enabled| is true.
GdkPixbuf* GetPixbufImpl(int id, bool rtl_enabled) const;
#endif
+ mutable ImageCache image_cache_;
+
+ // Keep images generated for theme cache in their own place, so we can lock
+ // them on WRITE from UI thread and READ from file thread. Read from UI
+ // thread will be allowed unlocked, because no other thread has write
+ // access to the cache.
+ mutable ImageCache themed_image_cache_;
+
#if defined(OS_LINUX)
typedef std::map<int, GdkPixbuf*> GdkPixbufMap;
mutable GdkPixbufMap gdk_pixbufs_;
@@ -202,10 +374,25 @@ class BrowserThemeProvider : public NonThreadSafe,
mutable NSColorMap nscolor_cache_;
#endif
+ mutable ImagesDiskCache images_disk_cache_;
+
ResourceBundle& rb_;
Profile* profile_;
- scoped_refptr<BrowserThemePack> theme_pack_;
+ ImageMap images_;
+ ColorMap colors_;
+ TintMap tints_;
+ mutable RawDataMap raw_data_;
+ DisplayPropertyMap display_properties_;
+
+ // Reverse of theme_resources_map, so we can cache images properly.
+ ResourceNameMap resource_names_;
+
+ // If true, process all images; if false, just load from disk.
+ bool process_images_;
+
+ // Where we will store our generated images.
+ FilePath image_dir_;
DISALLOW_COPY_AND_ASSIGN(BrowserThemeProvider);
};
diff --git a/chrome/browser/browser_theme_provider_mac.mm b/chrome/browser/browser_theme_provider_mac.mm
index ec3d4a8..65c2182 100644
--- a/chrome/browser/browser_theme_provider_mac.mm
+++ b/chrome/browser/browser_theme_provider_mac.mm
@@ -8,7 +8,6 @@
#include "app/gfx/color_utils.h"
#include "base/logging.h"
-#include "chrome/browser/browser_theme_pack.h"
#include "skia/ext/skia_utils_mac.h"
namespace {
@@ -76,8 +75,9 @@ NSColor* BrowserThemeProvider::GetNSColor(int id) const {
if (nscolor_iter != nscolor_cache_.end())
return nscolor_iter->second;
- SkColor sk_color;
- if (theme_pack_.get() && theme_pack_->GetColor(id, &sk_color)) {
+ ColorMap::const_iterator color_iter = colors_.find(GetColorKey(id));
+ if (color_iter != colors_.end()) {
+ const SkColor& sk_color = color_iter->second;
NSColor* color = [NSColor
colorWithCalibratedRed:SkColorGetR(sk_color)/255.0
green:SkColorGetG(sk_color)/255.0
@@ -102,8 +102,9 @@ NSColor* BrowserThemeProvider::GetNSColorTint(int id) const {
if (nscolor_iter != nscolor_cache_.end())
return nscolor_iter->second;
- color_utils::HSL tint;
- if (theme_pack_.get() && theme_pack_->GetTint(id, &tint)) {
+ TintMap::const_iterator tint_iter = tints_.find(GetTintKey(id));
+ if (tint_iter != tints_.end()) {
+ color_utils::HSL tint = tint_iter->second;
CGFloat hue, saturation, brightness;
HSLToHSB(tint, &hue, &saturation, &brightness);
diff --git a/chrome/browser/browser_theme_provider_unittest.cc b/chrome/browser/browser_theme_provider_unittest.cc
index 533c7af..6556a56 100644
--- a/chrome/browser/browser_theme_provider_unittest.cc
+++ b/chrome/browser/browser_theme_provider_unittest.cc
@@ -8,7 +8,87 @@
#include "base/values.h"
#include "base/json/json_reader.h"
-TEST(BrowserThemeProviderTest, AlignmentConversion) {
+class BrowserThemeProviderTest : public ::testing::Test {
+ public:
+ // Transformation for link underline colors.
+ SkColor BuildThirdOpacity(SkColor color_link) {
+ return SkColorSetA(color_link, SkColorGetA(color_link) / 3);
+ }
+
+ // Returns a mapping from each COLOR_* constant to the default value for this
+ // constant. Callers get this map, and then modify expected values and then
+ // run the resulting thing through VerifyColorMap().
+ std::map<int, SkColor> GetDefaultColorMap() {
+ std::map<int, SkColor> colors;
+ colors[BrowserThemeProvider::COLOR_FRAME] =
+ BrowserThemeProvider::kDefaultColorFrame;
+ colors[BrowserThemeProvider::COLOR_FRAME_INACTIVE] =
+ BrowserThemeProvider::kDefaultColorFrameInactive;
+ colors[BrowserThemeProvider::COLOR_FRAME_INCOGNITO] =
+ BrowserThemeProvider::kDefaultColorFrameIncognito;
+ colors[BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE] =
+ BrowserThemeProvider::kDefaultColorFrameIncognitoInactive;
+ colors[BrowserThemeProvider::COLOR_TOOLBAR] =
+ BrowserThemeProvider::kDefaultColorToolbar;
+ colors[BrowserThemeProvider::COLOR_TAB_TEXT] =
+ BrowserThemeProvider::kDefaultColorTabText;
+ colors[BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT] =
+ BrowserThemeProvider::kDefaultColorBackgroundTabText;
+ colors[BrowserThemeProvider::COLOR_BOOKMARK_TEXT] =
+ BrowserThemeProvider::kDefaultColorBookmarkText;
+ colors[BrowserThemeProvider::COLOR_NTP_BACKGROUND] =
+ BrowserThemeProvider::kDefaultColorNTPBackground;
+ colors[BrowserThemeProvider::COLOR_NTP_TEXT] =
+ BrowserThemeProvider::kDefaultColorNTPText;
+ colors[BrowserThemeProvider::COLOR_NTP_LINK] =
+ BrowserThemeProvider::kDefaultColorNTPLink;
+ colors[BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE] =
+ BuildThirdOpacity(BrowserThemeProvider::kDefaultColorNTPLink);
+ colors[BrowserThemeProvider::COLOR_NTP_HEADER] =
+ BrowserThemeProvider::kDefaultColorNTPHeader;
+ colors[BrowserThemeProvider::COLOR_NTP_SECTION] =
+ BrowserThemeProvider::kDefaultColorNTPSection;
+ colors[BrowserThemeProvider::COLOR_NTP_SECTION_TEXT] =
+ BrowserThemeProvider::kDefaultColorNTPSectionText;
+ colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK] =
+ BrowserThemeProvider::kDefaultColorNTPSectionLink;
+ colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE] =
+ BuildThirdOpacity(BrowserThemeProvider::kDefaultColorNTPSectionLink);
+ colors[BrowserThemeProvider::COLOR_CONTROL_BACKGROUND] =
+ BrowserThemeProvider::kDefaultColorControlBackground;
+ colors[BrowserThemeProvider::COLOR_BUTTON_BACKGROUND] =
+ BrowserThemeProvider::kDefaultColorButtonBackground;
+
+ return colors;
+ }
+
+ void VerifyColorMap(const std::map<int, SkColor>& color_map) {
+ for (std::map<int, SkColor>::const_iterator it = color_map.begin();
+ it != color_map.end(); ++it) {
+ EXPECT_EQ(it->second, provider_.GetColor(it->first));
+ }
+ }
+
+ void LoadColorJSON(const std::string& json) {
+ scoped_ptr<Value> value(base::JSONReader::Read(json, false));
+ ASSERT_TRUE(value->IsType(Value::TYPE_DICTIONARY));
+ provider_.SetColorData(static_cast<DictionaryValue*>(value.get()));
+ }
+
+ void LoadTintJSON(const std::string& json) {
+ scoped_ptr<Value> value(base::JSONReader::Read(json, false));
+ ASSERT_TRUE(value->IsType(Value::TYPE_DICTIONARY));
+ provider_.SetTintData(static_cast<DictionaryValue*>(value.get()));
+ }
+
+ void GenerateFrameColors() {
+ provider_.GenerateFrameColors();
+ }
+
+ BrowserThemeProvider provider_;
+};
+
+TEST_F(BrowserThemeProviderTest, AlignmentConversion) {
// Verify that we get out what we put in.
std::string top_left = "top left";
int alignment = BrowserThemeProvider::StringToAlignment(top_left);
@@ -33,7 +113,7 @@ TEST(BrowserThemeProviderTest, AlignmentConversion) {
EXPECT_EQ("", BrowserThemeProvider::AlignmentToString(alignment));
}
-TEST(BrowserThemeProviderTest, AlignmentConversionInput) {
+TEST_F(BrowserThemeProviderTest, AlignmentConversionInput) {
// Verify that we output in an expected format.
int alignment = BrowserThemeProvider::StringToAlignment("right bottom");
EXPECT_EQ("bottom right", BrowserThemeProvider::AlignmentToString(alignment));
@@ -50,3 +130,98 @@ TEST(BrowserThemeProviderTest, AlignmentConversionInput) {
alignment = BrowserThemeProvider::StringToAlignment("new zealandtop");
EXPECT_EQ("", BrowserThemeProvider::AlignmentToString(alignment));
}
+
+TEST_F(BrowserThemeProviderTest, ColorSanityCheck) {
+ // Make sure that BrowserThemeProvider returns all the default colors if it
+ // isn't provided any color overrides.
+ std::map<int, SkColor> colors = GetDefaultColorMap();
+ VerifyColorMap(colors);
+}
+
+TEST_F(BrowserThemeProviderTest, DeriveUnderlineLinkColor) {
+ // If we specify a link color, but don't specify the underline color, the
+ // theme provider should create one.
+ std::string color_json = "{ \"ntp_link\": [128, 128, 128, 1],"
+ " \"ntp_section_link\": [128, 128, 128, 1] }";
+ LoadColorJSON(color_json);
+
+ std::map<int, SkColor> colors = GetDefaultColorMap();
+ SkColor link_color = SkColorSetARGB(255, 128, 128, 128);
+ colors[BrowserThemeProvider::COLOR_NTP_LINK] = link_color;
+ colors[BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE] =
+ BuildThirdOpacity(link_color);
+ colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK] = link_color;
+ colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE] =
+ BuildThirdOpacity(link_color);
+
+ VerifyColorMap(colors);
+}
+
+TEST_F(BrowserThemeProviderTest, ProvideUnderlineLinkColor) {
+ // If we specify the underline color, it shouldn't try to generate one.x
+ std::string color_json = "{ \"ntp_link\": [128, 128, 128],"
+ " \"ntp_link_underline\": [255, 255, 255],"
+ " \"ntp_section_link\": [128, 128, 128],"
+ " \"ntp_section_link_underline\": [255, 255, 255]"
+ "}";
+ LoadColorJSON(color_json);
+
+ std::map<int, SkColor> colors = GetDefaultColorMap();
+ SkColor link_color = SkColorSetRGB(128, 128, 128);
+ SkColor underline_color = SkColorSetRGB(255, 255, 255);
+ colors[BrowserThemeProvider::COLOR_NTP_LINK] = link_color;
+ colors[BrowserThemeProvider::COLOR_NTP_LINK_UNDERLINE] = underline_color;
+ colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK] = link_color;
+ colors[BrowserThemeProvider::COLOR_NTP_SECTION_LINK_UNDERLINE] =
+ underline_color;
+
+ VerifyColorMap(colors);
+}
+
+TEST_F(BrowserThemeProviderTest, UseSectionColorAsNTPHeader) {
+ std::string color_json = "{ \"ntp_section\": [190, 190, 190] }";
+ LoadColorJSON(color_json);
+
+ std::map<int, SkColor> colors = GetDefaultColorMap();
+ SkColor ntp_color = SkColorSetRGB(190, 190, 190);
+ colors[BrowserThemeProvider::COLOR_NTP_HEADER] = ntp_color;
+ colors[BrowserThemeProvider::COLOR_NTP_SECTION] = ntp_color;
+ VerifyColorMap(colors);
+}
+
+TEST_F(BrowserThemeProviderTest, ProvideNtpHeaderColor) {
+ std::string color_json = "{ \"ntp_header\": [120, 120, 120], "
+ " \"ntp_section\": [190, 190, 190] }";
+ LoadColorJSON(color_json);
+
+ std::map<int, SkColor> colors = GetDefaultColorMap();
+ SkColor ntp_header = SkColorSetRGB(120, 120, 120);
+ SkColor ntp_section = SkColorSetRGB(190, 190, 190);
+ colors[BrowserThemeProvider::COLOR_NTP_HEADER] = ntp_header;
+ colors[BrowserThemeProvider::COLOR_NTP_SECTION] = ntp_section;
+ VerifyColorMap(colors);
+}
+
+TEST_F(BrowserThemeProviderTest, DefaultTintingDefaultColors) {
+ // Default tints for buttons and frames...are no tints! So make sure that
+ // when we try to generate frame colors, we end up with the same.
+ GenerateFrameColors();
+
+ std::map<int, SkColor> colors = GetDefaultColorMap();
+ colors[BrowserThemeProvider::COLOR_FRAME] =
+ HSLShift(BrowserThemeProvider::kDefaultColorFrame,
+ BrowserThemeProvider::kDefaultTintFrame);
+ colors[BrowserThemeProvider::COLOR_FRAME_INACTIVE] =
+ HSLShift(BrowserThemeProvider::kDefaultColorFrame,
+ BrowserThemeProvider::kDefaultTintFrameInactive);
+ colors[BrowserThemeProvider::COLOR_FRAME_INCOGNITO] =
+ HSLShift(BrowserThemeProvider::kDefaultColorFrame,
+ BrowserThemeProvider::kDefaultTintFrameIncognito);
+ colors[BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE] =
+ HSLShift(BrowserThemeProvider::kDefaultColorFrame,
+ BrowserThemeProvider::kDefaultTintFrameIncognitoInactive);
+ VerifyColorMap(colors);
+}
+
+// TODO(erg): Test more tinting combinations. For example, with non-default
+// colors or when providing tints.
diff --git a/chrome/browser/cocoa/download_shelf_controller.mm b/chrome/browser/cocoa/download_shelf_controller.mm
index ae9395b..5d494fc 100644
--- a/chrome/browser/cocoa/download_shelf_controller.mm
+++ b/chrome/browser/cocoa/download_shelf_controller.mm
@@ -114,12 +114,10 @@ const NSTimeInterval kDownloadShelfCloseDuration = 0.12;
BOOL useDefaultColor = YES;
if (bridge_.get() && bridge_->browser() && bridge_->browser()->profile()) {
ThemeProvider* provider = bridge_->browser()->profile()->GetThemeProvider();
- if (provider) {
+ if (provider)
useDefaultColor = provider->GetColor(
BrowserThemeProvider::COLOR_BOOKMARK_TEXT) ==
- BrowserThemeProvider::GetDefaultColor(
- BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
- }
+ BrowserThemeProvider::kDefaultColorBookmarkText;
}
NSColor* color = useDefaultColor ?
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
index caea07d..879cbb2 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -27,9 +27,7 @@ ThemeInstalledInfoBarDelegate::ThemeInstalledInfoBarDelegate(
void ThemeInstalledInfoBarDelegate::InfoBarClosed() {
ExtensionsService* service = profile_->GetExtensionsService();
- // Only delete the theme if we've installed a new theme and not the same
- // theme on top of the current one.
- if (service && previous_theme_id_ != new_theme_id_) {
+ if (service) {
std::string uninstall_id;
if (was_canceled_)
uninstall_id = new_theme_id_;
diff --git a/chrome/browser/gtk/download_shelf_gtk.cc b/chrome/browser/gtk/download_shelf_gtk.cc
index 6d94b9f..8601855 100644
--- a/chrome/browser/gtk/download_shelf_gtk.cc
+++ b/chrome/browser/gtk/download_shelf_gtk.cc
@@ -201,8 +201,7 @@ void DownloadShelfGtk::Observe(NotificationType type,
// bad for some dark themes.
bool use_default_color = theme_provider_->GetColor(
BrowserThemeProvider::COLOR_BOOKMARK_TEXT) ==
- BrowserThemeProvider::GetDefaultColor(
- BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
+ BrowserThemeProvider::kDefaultColorBookmarkText;
GdkColor bookmark_color = theme_provider_->GetGdkColor(
BrowserThemeProvider::COLOR_BOOKMARK_TEXT);
gtk_chrome_link_button_set_normal_color(
diff --git a/chrome/browser/gtk/gtk_theme_provider.cc b/chrome/browser/gtk/gtk_theme_provider.cc
index 9330f30..4f35110 100644
--- a/chrome/browser/gtk/gtk_theme_provider.cc
+++ b/chrome/browser/gtk/gtk_theme_provider.cc
@@ -8,8 +8,6 @@
#include "app/gfx/color_utils.h"
#include "app/gfx/gtk_util.h"
-#include "app/gfx/skbitmap_operations.h"
-#include "base/stl_util-inl.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/gtk/cairo_cached_surface.h"
@@ -59,26 +57,6 @@ SkColor GdkToSkColor(GdkColor* color) {
color->blue >> 8);
}
-// A list of images that we provide while in gtk mode.
-const int kThemeImages[] = {
- IDR_THEME_TOOLBAR,
- IDR_THEME_TAB_BACKGROUND,
- IDR_THEME_TAB_BACKGROUND_INCOGNITO,
- IDR_THEME_FRAME,
- IDR_THEME_FRAME_INACTIVE,
- IDR_THEME_FRAME_INCOGNITO,
- IDR_THEME_FRAME_INCOGNITO_INACTIVE,
-};
-
-bool IsOverridableImage(int id) {
- for (size_t i = 0; i < arraysize(kThemeImages); ++i) {
- if (kThemeImages[i] == id)
- return true;
- }
-
- return false;
-}
-
} // namespace
GtkWidget* GtkThemeProvider::icon_widget_ = NULL;
@@ -106,9 +84,9 @@ GtkThemeProvider::~GtkThemeProvider() {
gtk_widget_destroy(fake_window_);
fake_label_.Destroy();
- // We have to call this because FreePlatformCached() in ~BrowserThemeProvider
- // doesn't call the right virutal FreePlatformCaches.
- FreePlatformCaches();
+ // We have to call this because ClearCaches in ~BrowserThemeProvider doesn't
+ // call the right virutal FreePlatformCaches.
+ FreePerDisplaySurfaces();
// Disconnect from the destroy signal of any redisual widgets in
// |chrome_buttons_|.
@@ -125,39 +103,6 @@ void GtkThemeProvider::Init(Profile* profile) {
BrowserThemeProvider::Init(profile);
}
-SkBitmap* GtkThemeProvider::GetBitmapNamed(int id) const {
- if (use_gtk_ && IsOverridableImage(id)) {
- // Try to get our cached version:
- ImageCache::const_iterator it = gtk_images_.find(id);
- if (it != gtk_images_.end())
- return it->second;
-
- // We haven't built this image yet:
- SkBitmap* bitmap = GenerateGtkThemeBitmap(id);
- gtk_images_[id] = bitmap;
- return bitmap;
- }
-
- return BrowserThemeProvider::GetBitmapNamed(id);
-}
-
-SkColor GtkThemeProvider::GetColor(int id) const {
- if (use_gtk_) {
- ColorMap::const_iterator it = colors_.find(id);
- if (it != colors_.end())
- return it->second;
- }
-
- return BrowserThemeProvider::GetColor(id);
-}
-
-bool GtkThemeProvider::HasCustomImage(int id) const {
- if (use_gtk_)
- return IsOverridableImage(id);
-
- return BrowserThemeProvider::HasCustomImage(id);
-}
-
void GtkThemeProvider::InitThemesFor(NotificationObserver* observer) {
observer->Observe(NotificationType::BROWSER_THEME_CHANGED,
Source<ThemeProvider>(this),
@@ -400,10 +345,40 @@ void GtkThemeProvider::NotifyThemeChanged() {
}
}
+SkBitmap* GtkThemeProvider::LoadThemeBitmap(int id) const {
+ if (use_gtk_) {
+ if (id == IDR_THEME_TOOLBAR) {
+ GtkStyle* style = gtk_rc_get_style(fake_window_);
+ GdkColor* color = &style->bg[GTK_STATE_NORMAL];
+ SkBitmap* bitmap = new SkBitmap;
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config,
+ kToolbarImageWidth, kToolbarImageHeight);
+ bitmap->allocPixels();
+ bitmap->eraseRGB(color->red >> 8, color->green >> 8, color->blue >> 8);
+ return bitmap;
+ }
+ if ((id == IDR_THEME_TAB_BACKGROUND) ||
+ (id == IDR_THEME_TAB_BACKGROUND_INCOGNITO))
+ return GenerateTabBackgroundBitmapImpl(id);
+ }
+
+ return BrowserThemeProvider::LoadThemeBitmap(id);
+}
+
+void GtkThemeProvider::SaveThemeBitmap(const std::string resource_name,
+ int id) const {
+ if (!use_gtk_) {
+ // Prevent us from writing out our mostly unused resources in gtk theme
+ // mode. Simply preventing us from writing this data out in gtk mode isn't
+ // the best design, but this would probably be a very invasive change on
+ // all three platforms otherwise.
+ BrowserThemeProvider::SaveThemeBitmap(resource_name, id);
+ }
+}
+
void GtkThemeProvider::FreePlatformCaches() {
BrowserThemeProvider::FreePlatformCaches();
FreePerDisplaySurfaces();
- STLDeleteValues(&gtk_images_);
}
// static
@@ -500,35 +475,34 @@ void GtkThemeProvider::LoadGtkValues() {
}
}
- SetThemeTintFromGtk(BrowserThemeProvider::TINT_BUTTONS, &button_color);
- SetThemeTintFromGtk(BrowserThemeProvider::TINT_FRAME, &frame_color);
- SetThemeTintFromGtk(BrowserThemeProvider::TINT_FRAME_INCOGNITO, &frame_color);
- SetThemeTintFromGtk(BrowserThemeProvider::TINT_BACKGROUND_TAB, &frame_color);
-
- SetThemeColorFromGtk(BrowserThemeProvider::COLOR_FRAME, &frame_color);
- BuildTintedFrameColor(BrowserThemeProvider::COLOR_FRAME_INACTIVE,
- BrowserThemeProvider::TINT_FRAME_INACTIVE);
- BuildTintedFrameColor(BrowserThemeProvider::COLOR_FRAME_INCOGNITO,
- BrowserThemeProvider::TINT_FRAME_INCOGNITO);
- BuildTintedFrameColor(BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE,
- BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE);
-
+ SetThemeColorFromGtk(kColorFrame, &frame_color);
// Skip COLOR_FRAME_INACTIVE and the incognito colors, as they will be
- // autogenerated from tints. TODO(erg): Still true?
- SetThemeColorFromGtk(BrowserThemeProvider::COLOR_TOOLBAR, &toolbar_color);
- SetThemeColorFromGtk(BrowserThemeProvider::COLOR_TAB_TEXT, &label_color);
- SetThemeColorFromGtk(BrowserThemeProvider::COLOR_BOOKMARK_TEXT, &label_color);
- SetThemeColorFromGtk(BrowserThemeProvider::COLOR_CONTROL_BACKGROUND,
+ // autogenerated from tints.
+ SetThemeColorFromGtk(kColorToolbar, &toolbar_color);
+ SetThemeColorFromGtk(kColorTabText, &label_color);
+ SetThemeColorFromGtk(kColorBookmarkText, &label_color);
+ SetThemeColorFromGtk(kColorControlBackground,
&window_style->bg[GTK_STATE_NORMAL]);
- SetThemeColorFromGtk(BrowserThemeProvider::COLOR_BUTTON_BACKGROUND,
+ SetThemeColorFromGtk(kColorButtonBackground,
&window_style->bg[GTK_STATE_NORMAL]);
+ SetThemeTintFromGtk(kTintButtons, &button_color,
+ kDefaultTintButtons);
+ SetThemeTintFromGtk(kTintFrame, &frame_color,
+ kDefaultTintFrame);
+ SetThemeTintFromGtk(kTintFrameIncognito,
+ &frame_color,
+ kDefaultTintFrameIncognito);
+ SetThemeTintFromGtk(kTintBackgroundTab,
+ &frame_color,
+ kDefaultTintBackgroundTab);
+
// The inactive frame color never occurs naturally in the theme, as it is a
// tinted version of |frame_color|. We generate another color based on the
// background tab color, with the lightness and saturation moved in the
// opposite direction. (We don't touch the hue, since there should be subtle
// hints of the color in the text.)
- color_utils::HSL inactive_tab_text_hsl = tints_[TINT_BACKGROUND_TAB];
+ color_utils::HSL inactive_tab_text_hsl = GetTint(TINT_BACKGROUND_TAB);
if (inactive_tab_text_hsl.l < 0.5)
inactive_tab_text_hsl.l = kDarkInactiveLuminance;
else
@@ -539,26 +513,32 @@ void GtkThemeProvider::LoadGtkValues() {
else
inactive_tab_text_hsl.s = kLightInactiveSaturation;
- colors_[BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT] =
- color_utils::HSLToSkColor(inactive_tab_text_hsl, 255);
+ SetColor(kColorBackgroundTabText,
+ color_utils::HSLToSkColor(inactive_tab_text_hsl, 255));
// The inactive color/tint is special: We *must* use the exact insensitive
// color for all inactive windows, otherwise we end up neon pink half the
// time.
- SetThemeColorFromGtk(BrowserThemeProvider::COLOR_FRAME_INACTIVE,
- &inactive_frame_color);
- SetTintToExactColor(BrowserThemeProvider::TINT_FRAME_INACTIVE,
- &inactive_frame_color);
- SetTintToExactColor(BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE,
- &inactive_frame_color);
+ SetThemeColorFromGtk(kColorFrameInactive, &inactive_frame_color);
+ SetThemeTintFromGtk(kTintFrameInactive, &inactive_frame_color,
+ kExactColor);
+ SetThemeTintFromGtk(kTintFrameIncognitoInactive, &inactive_frame_color,
+ kExactColor);
+
+ force_process_images();
+ GenerateFrameColors();
+ AutoLock lock(themed_image_cache_lock_);
+ GenerateFrameImages();
}
-void GtkThemeProvider::SetThemeColorFromGtk(int id, GdkColor* color) {
- colors_[id] = GdkToSkColor(color);
+void GtkThemeProvider::SetThemeColorFromGtk(const char* id, GdkColor* color) {
+ SetColor(id, GdkToSkColor(color));
}
-void GtkThemeProvider::SetThemeTintFromGtk(int id, GdkColor* color) {
- color_utils::HSL default_tint = GetDefaultTint(id);
+void GtkThemeProvider::SetThemeTintFromGtk(
+ const char* id,
+ GdkColor* color,
+ const color_utils::HSL& default_tint) {
color_utils::HSL hsl;
color_utils::SkColorToHSL(GdkToSkColor(color), &hsl);
@@ -567,19 +547,7 @@ void GtkThemeProvider::SetThemeTintFromGtk(int id, GdkColor* color) {
if (default_tint.l != -1)
hsl.l = default_tint.l;
-
- tints_[id] = hsl;
-}
-
-void GtkThemeProvider::BuildTintedFrameColor(int color_id, int tint_id) {
- colors_[color_id] = HSLShift(colors_[BrowserThemeProvider::COLOR_FRAME],
- tints_[tint_id]);
-}
-
-void GtkThemeProvider::SetTintToExactColor(int id, GdkColor* color) {
- color_utils::HSL hsl;
- color_utils::SkColorToHSL(GdkToSkColor(color), &hsl);
- tints_[id] = hsl;
+ SetTint(id, hsl);
}
void GtkThemeProvider::FreePerDisplaySurfaces() {
@@ -593,55 +561,6 @@ void GtkThemeProvider::FreePerDisplaySurfaces() {
per_display_surfaces_.clear();
}
-SkBitmap* GtkThemeProvider::GenerateGtkThemeBitmap(int id) const {
- switch (id) {
- case IDR_THEME_TOOLBAR: {
- GtkStyle* style = gtk_rc_get_style(fake_window_);
- GdkColor* color = &style->bg[GTK_STATE_NORMAL];
- SkBitmap* bitmap = new SkBitmap;
- bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- kToolbarImageWidth, kToolbarImageHeight);
- bitmap->allocPixels();
- bitmap->eraseRGB(color->red >> 8, color->green >> 8, color->blue >> 8);
- return bitmap;
- }
- case IDR_THEME_TAB_BACKGROUND:
- return GenerateTabImage(IDR_THEME_FRAME);
- case IDR_THEME_TAB_BACKGROUND_INCOGNITO:
- return GenerateTabImage(IDR_THEME_FRAME_INCOGNITO);
- case IDR_THEME_FRAME:
- return GenerateFrameImage(BrowserThemeProvider::TINT_FRAME);
- case IDR_THEME_FRAME_INACTIVE:
- return GenerateFrameImage(BrowserThemeProvider::TINT_FRAME_INACTIVE);
- case IDR_THEME_FRAME_INCOGNITO:
- return GenerateFrameImage(BrowserThemeProvider::TINT_FRAME_INCOGNITO);
- case IDR_THEME_FRAME_INCOGNITO_INACTIVE: {
- return GenerateFrameImage(
- BrowserThemeProvider::TINT_FRAME_INCOGNITO_INACTIVE);
- }
- }
-
- NOTREACHED() << "Invalid bitmap request " << id;
- return NULL;
-}
-
-SkBitmap* GtkThemeProvider::GenerateFrameImage(int tint_id) const {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- scoped_ptr<SkBitmap> frame(new SkBitmap(*rb.GetBitmapNamed(IDR_THEME_FRAME)));
- TintMap::const_iterator it = tints_.find(tint_id);
- DCHECK(it != tints_.end());
- return new SkBitmap(SkBitmapOperations::CreateHSLShiftedBitmap(*frame,
- it->second));
-}
-
-SkBitmap* GtkThemeProvider::GenerateTabImage(int base_id) const {
- SkBitmap* base_image = GetBitmapNamed(base_id);
- SkBitmap bg_tint = SkBitmapOperations::CreateHSLShiftedBitmap(
- *base_image, GetTint(BrowserThemeProvider::TINT_BACKGROUND_TAB));
- return new SkBitmap(SkBitmapOperations::CreateTiledBitmap(
- bg_tint, 0, 0, bg_tint.width(), bg_tint.height()));
-}
-
void GtkThemeProvider::OnDestroyChromeButton(GtkWidget* button,
GtkThemeProvider* provider) {
std::vector<GtkWidget*>::iterator it =
diff --git a/chrome/browser/gtk/gtk_theme_provider.h b/chrome/browser/gtk/gtk_theme_provider.h
index 44fed99..60d72e7 100644
--- a/chrome/browser/gtk/gtk_theme_provider.h
+++ b/chrome/browser/gtk/gtk_theme_provider.h
@@ -40,9 +40,6 @@ class GtkThemeProvider : public BrowserThemeProvider,
// Sets that we aren't using the system theme, then calls
// BrowserThemeProvider's implementation.
virtual void Init(Profile* profile);
- virtual SkBitmap* GetBitmapNamed(int id) const;
- virtual SkColor GetColor(int id) const;
- virtual bool HasCustomImage(int id) const;
virtual void SetTheme(Extension* extension);
virtual void UseDefaultTheme();
virtual void SetNativeTheme();
@@ -89,17 +86,24 @@ class GtkThemeProvider : public BrowserThemeProvider,
static GdkPixbuf* GetFolderIcon(bool native);
static GdkPixbuf* GetDefaultFavicon(bool native);
- private:
- typedef std::map<int, SkColor> ColorMap;
- typedef std::map<int, color_utils::HSL> TintMap;
- typedef std::map<int, SkBitmap*> ImageCache;
+ protected:
+ // Possibly creates a theme specific version of theme_toolbar_default.
+ // (minimally acceptable version right now, which is just a fill of the bg
+ // color; this should instead invoke gtk_draw_box(...) for complex theme
+ // engines.)
+ virtual SkBitmap* LoadThemeBitmap(int id) const;
+ private:
// Load theme data from preferences, possibly picking colors from GTK.
virtual void LoadThemePrefs();
// Let all the browser views know that themes have changed.
virtual void NotifyThemeChanged();
+ // If use_gtk_ is true, completely ignores this call. Otherwise passes it to
+ // the superclass.
+ virtual void SaveThemeBitmap(const std::string resource_name, int id) const;
+
// Additionally frees the CairoCachedSurfaces.
virtual void FreePlatformCaches();
@@ -111,10 +115,9 @@ class GtkThemeProvider : public BrowserThemeProvider,
void LoadGtkValues();
// Sets the underlying theme colors/tints from a GTK color.
- void SetThemeColorFromGtk(int id, GdkColor* color);
- void SetThemeTintFromGtk(int id, GdkColor* color);
- void BuildTintedFrameColor(int color_id, int tint_id);
- void SetTintToExactColor(int id, GdkColor* color);
+ void SetThemeColorFromGtk(const char* id, GdkColor* color);
+ void SetThemeTintFromGtk(const char* id, GdkColor* color,
+ const color_utils::HSL& default_tint);
// Split out from FreePlatformCaches so it can be called in our destructor;
// FreePlatformCaches() is called from the BrowserThemeProvider's destructor,
@@ -122,16 +125,6 @@ class GtkThemeProvider : public BrowserThemeProvider,
// points to GtkThemeProvider's version.
void FreePerDisplaySurfaces();
- // Lazily generates each bitmap used in the gtk theme.
- SkBitmap* GenerateGtkThemeBitmap(int id) const;
-
- // Tints IDR_THEME_FRAME based based on |tint_id|. Used during lazy
- // generation of the gtk theme bitmaps.
- SkBitmap* GenerateFrameImage(int tint_id) const;
-
- // Takes the base frame image |base_id| and tints it with |tint_id|.
- SkBitmap* GenerateTabImage(int base_id) const;
-
// A notification from the GtkChromeButton GObject destructor that we should
// remove it from our internal list.
static void OnDestroyChromeButton(GtkWidget* button,
@@ -149,15 +142,6 @@ class GtkThemeProvider : public BrowserThemeProvider,
// them of theme changes.
std::vector<GtkWidget*> chrome_buttons_;
- // Tints and colors calculated by LoadGtkValues() that are given to the
- // caller while |use_gtk_| is true.
- ColorMap colors_;
- TintMap tints_;
-
- // Image cache of lazily created images, created when requested by
- // GetBitmapNamed().
- mutable ImageCache gtk_images_;
-
// Cairo surfaces for each GdkDisplay.
typedef std::map<int, CairoCachedSurface*> CairoCachedSurfaceMap;
typedef std::map<GdkDisplay*, CairoCachedSurfaceMap> PerDisplaySurfaceMap;
diff --git a/chrome/browser/gtk/gtk_theme_provider_unittest.cc b/chrome/browser/gtk/gtk_theme_provider_unittest.cc
index 93012ba..c3b85cb 100644
--- a/chrome/browser/gtk/gtk_theme_provider_unittest.cc
+++ b/chrome/browser/gtk/gtk_theme_provider_unittest.cc
@@ -35,6 +35,11 @@ class GtkThemeProviderTest : public testing::Test {
provider_ = GtkThemeProvider::GetFrom(&profile_);
}
+ void UseThemeProvider(GtkThemeProvider* provider) {
+ profile_.UseThemeProvider(provider);
+ provider_ = GtkThemeProvider::GetFrom(&profile_);
+ }
+
protected:
TestingProfile profile_;
@@ -46,11 +51,42 @@ TEST_F(GtkThemeProviderTest, DefaultValues) {
BuildProvider();
// Test that we get the default theme colors back when in normal mode.
- for (int i = BrowserThemeProvider::COLOR_FRAME;
- i <= BrowserThemeProvider::COLOR_BUTTON_BACKGROUND; ++i) {
- EXPECT_EQ(provider_->GetColor(i), BrowserThemeProvider::GetDefaultColor(i))
- << "Wrong default color for " << i;
- }
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_FRAME),
+ BrowserThemeProvider::kDefaultColorFrame);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_FRAME_INACTIVE),
+ BrowserThemeProvider::kDefaultColorFrameInactive);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_FRAME_INCOGNITO),
+ BrowserThemeProvider::kDefaultColorFrameIncognito);
+ EXPECT_EQ(provider_->GetColor(
+ BrowserThemeProvider::COLOR_FRAME_INCOGNITO_INACTIVE),
+ BrowserThemeProvider::kDefaultColorFrameIncognitoInactive);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_TOOLBAR),
+ BrowserThemeProvider::kDefaultColorToolbar);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_TAB_TEXT),
+ BrowserThemeProvider::kDefaultColorTabText);
+ EXPECT_EQ(provider_->GetColor(
+ BrowserThemeProvider::COLOR_BACKGROUND_TAB_TEXT),
+ BrowserThemeProvider::kDefaultColorBackgroundTabText);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT),
+ BrowserThemeProvider::kDefaultColorBookmarkText);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_NTP_BACKGROUND),
+ BrowserThemeProvider::kDefaultColorNTPBackground);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_NTP_TEXT),
+ BrowserThemeProvider::kDefaultColorNTPText);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_NTP_LINK),
+ BrowserThemeProvider::kDefaultColorNTPLink);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_NTP_HEADER),
+ BrowserThemeProvider::kDefaultColorNTPHeader);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_NTP_SECTION),
+ BrowserThemeProvider::kDefaultColorNTPSection);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_NTP_SECTION_TEXT),
+ BrowserThemeProvider::kDefaultColorNTPSectionText);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_NTP_SECTION_LINK),
+ BrowserThemeProvider::kDefaultColorNTPSectionLink);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_CONTROL_BACKGROUND),
+ BrowserThemeProvider::kDefaultColorControlBackground);
+ EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_BUTTON_BACKGROUND),
+ BrowserThemeProvider::kDefaultColorButtonBackground);
}
TEST_F(GtkThemeProviderTest, UsingGtkValues) {
@@ -68,3 +104,32 @@ TEST_F(GtkThemeProviderTest, UsingGtkValues) {
EXPECT_EQ(provider_->GetColor(BrowserThemeProvider::COLOR_TAB_TEXT),
GdkToSkColor(&label_color));
}
+
+// Helper class to GtkThemeProviderTest.UsingGtkFrame.
+class ImageVerifierGtkThemeProvider : public GtkThemeProvider {
+ public:
+ ImageVerifierGtkThemeProvider() : theme_toolbar_(NULL) { }
+
+ virtual SkBitmap* LoadThemeBitmap(int id) const {
+ if (id != IDR_THEME_TOOLBAR)
+ return GtkThemeProvider::LoadThemeBitmap(id);
+ theme_toolbar_ = GtkThemeProvider::LoadThemeBitmap(id);
+ return theme_toolbar_;
+ }
+
+ mutable SkBitmap* theme_toolbar_;
+};
+
+TEST_F(GtkThemeProviderTest, InjectsToolbar) {
+ SetUseGtkTheme(true);
+ ImageVerifierGtkThemeProvider* verifier_provider =
+ new ImageVerifierGtkThemeProvider;
+ UseThemeProvider(verifier_provider);
+
+ // Make sure the image we get from the public BrowserThemeProvider interface
+ // is the one we injected through GtkThemeProvider.
+ SkBitmap* image = provider_->GetBitmapNamed(IDR_THEME_TOOLBAR);
+ EXPECT_TRUE(verifier_provider->theme_toolbar_);
+ EXPECT_TRUE(image);
+ EXPECT_EQ(verifier_provider->theme_toolbar_, image);
+}
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index 3f5deee..22444f4 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -150,7 +150,6 @@ void Profile::RegisterUserPrefs(PrefService* prefs) {
#if defined(OS_LINUX)
prefs->RegisterBooleanPref(prefs::kUsesSystemTheme, false);
#endif
- prefs->RegisterFilePathPref(prefs::kCurrentThemePackFilename, FilePath());
prefs->RegisterStringPref(prefs::kCurrentThemeID,
UTF8ToWide(BrowserThemeProvider::kDefaultThemeID));
prefs->RegisterDictionaryPref(prefs::kCurrentThemeImages);
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 5ac8be1..21ab8e9 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -188,8 +188,6 @@
'browser/browser_process_impl.h',
'browser/browser_shutdown.cc',
'browser/browser_shutdown.h',
- 'browser/browser_theme_pack.cc',
- 'browser/browser_theme_pack.h',
'browser/browser_theme_provider_gtk.cc',
'browser/browser_theme_provider_mac.mm',
'browser/browser_theme_provider.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 801b6be..af198977 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -526,7 +526,6 @@
'browser/bookmarks/bookmark_table_model_unittest.cc',
'browser/bookmarks/bookmark_utils_unittest.cc',
'browser/browser_commands_unittest.cc',
- 'browser/browser_theme_pack_unittest.cc',
'browser/browser_theme_provider_unittest.cc',
'browser/browser_unittest.cc',
'browser/chrome_browser_application_mac_unittest.mm',
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 1b85a19..1a936b5 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -84,7 +84,7 @@ const FilePath::CharType kOffTheRecordMediaCacheDirname[] =
FPL("Incognito Media Cache");
const FilePath::CharType kAppCacheDirname[] = FPL("Application Cache");
const wchar_t kChromePluginDataDirname[] = L"Plugin Data";
-const FilePath::CharType kThemePackFilename[] = FPL("Cached Theme.pak");
+const FilePath::CharType kThemeImagesDirname[] = FPL("Cached Theme Images");
const FilePath::CharType kCookieFilename[] = FPL("Cookies");
const FilePath::CharType kExtensionsCookieFilename[] = FPL("Extension Cookies");
const FilePath::CharType kHistoryFilename[] = FPL("History");
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index ea79fd8..4473f32 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -40,7 +40,7 @@ extern const FilePath::CharType kMediaCacheDirname[];
extern const FilePath::CharType kOffTheRecordMediaCacheDirname[];
extern const FilePath::CharType kAppCacheDirname[];
extern const wchar_t kChromePluginDataDirname[];
-extern const FilePath::CharType kThemePackFilename[];
+extern const FilePath::CharType kThemeImagesDirname[];
extern const FilePath::CharType kCookieFilename[];
extern const FilePath::CharType kExtensionsCookieFilename[];
extern const FilePath::CharType kHistoryFilename[];
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 6c1edf9..acd77db 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -250,7 +250,6 @@ const wchar_t kPrintingPageFooterRight[] = L"printing.page.footer.right";
// GTK specific preference on whether we should match the system GTK theme.
const wchar_t kUsesSystemTheme[] = L"extensions.theme.use_system";
#endif
-const wchar_t kCurrentThemePackFilename[] = L"extensions.theme.pack";
const wchar_t kCurrentThemeID[] = L"extensions.theme.id";
const wchar_t kCurrentThemeImages[] = L"extensions.theme.images";
const wchar_t kCurrentThemeColors[] = L"extensions.theme.colors";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 8229a6f..d3095b1 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -101,7 +101,6 @@ extern const wchar_t kPrintingPageFooterRight[];
#if defined(OS_LINUX)
extern const wchar_t kUsesSystemTheme[];
#endif
-extern const wchar_t kCurrentThemePackFilename[];
extern const wchar_t kCurrentThemeID[];
extern const wchar_t kCurrentThemeImages[];
extern const wchar_t kCurrentThemeColors[];
diff --git a/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_inactive b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_inactive
new file mode 100644
index 0000000..c1099db
--- /dev/null
+++ b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_inactive
Binary files differ
diff --git a/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_incognito b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_incognito
new file mode 100644
index 0000000..5d73cfd
--- /dev/null
+++ b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_incognito
Binary files differ
diff --git a/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_incognito_inactive b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_incognito_inactive
new file mode 100644
index 0000000..78b69a4
--- /dev/null
+++ b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_incognito_inactive
Binary files differ
diff --git a/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_original b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_original
new file mode 100644
index 0000000..fbd9a95
--- /dev/null
+++ b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_frame_original
Binary files differ
diff --git a/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_tab_background_incognito b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_tab_background_incognito
new file mode 100644
index 0000000..be17ca5
--- /dev/null
+++ b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_tab_background_incognito
Binary files differ
diff --git a/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_tab_background_original b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_tab_background_original
new file mode 100644
index 0000000..90cc6b4
--- /dev/null
+++ b/chrome/test/data/profiles/complex_theme/Default/Cached Theme Images/theme_tab_background_original
Binary files differ
diff --git a/chrome/test/data/profiles/complex_theme/Default/Extensions/mblmlcbknbnfebdfjnolmcapmdofhmme/1.1/Cached Theme.pak b/chrome/test/data/profiles/complex_theme/Default/Extensions/mblmlcbknbnfebdfjnolmcapmdofhmme/1.1/Cached Theme.pak
deleted file mode 100644
index 0a76cb9..0000000
--- a/chrome/test/data/profiles/complex_theme/Default/Extensions/mblmlcbknbnfebdfjnolmcapmdofhmme/1.1/Cached Theme.pak
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/profiles/complex_theme/Default/PreferencesTemplate b/chrome/test/data/profiles/complex_theme/Default/PreferencesTemplate
index 7c3eb03..f869914 100644
--- a/chrome/test/data/profiles/complex_theme/Default/PreferencesTemplate
+++ b/chrome/test/data/profiles/complex_theme/Default/PreferencesTemplate
@@ -50,8 +50,39 @@
}
},
"theme": {
+ "colors": {
+ "bookmark_text": [ 0, 0, 0 ],
+ "frame": [ 57, 137, 194 ],
+ "ntp_background": [ 57, 137, 194 ],
+ "ntp_link": [ 0, 0, 0 ],
+ "ntp_section": [ 131, 138, 146, 0.8 ],
+ "ntp_section_link": [ 255, 255, 255 ],
+ "ntp_section_text": [ 255, 255, 255 ],
+ "ntp_text": [ 0, 0, 0 ],
+ "tab_background_text": [ 0, 0, 0 ],
+ "tab_text": [ 0, 0, 0 ],
+ "toolbar": [ 204, 208, 212 ]
+ },
"id": "mblmlcbknbnfebdfjnolmcapmdofhmme",
- "pack": "$1/Default/Extensions/mblmlcbknbnfebdfjnolmcapmdofhmme/1.1/Cached Theme.pak"
+ "images": {
+ "theme_button_background": "$1/Default/Extensions/mblmlcbknbnfebdfjnolmcapmdofhmme/1.1/i/agxjaHJvbWV0aGVtZXNyDAsSBEZpbGUYwsgCDA",
+ "theme_frame": "$1/Default/Cached Theme Images/theme_frame_original",
+ "theme_frame_inactive": "$1/Default/Cached Theme Images/theme_frame_inactive",
+ "theme_frame_incognito": "$1/Default/Cached Theme Images/theme_frame_incognito",
+ "theme_frame_incognito_inactive": "$1/Default/Cached Theme Images/theme_frame_incognito_inactive",
+ "theme_ntp_background": "$1/Default/Extensions/mblmlcbknbnfebdfjnolmcapmdofhmme/1.1/i/agxjaHJvbWV0aGVtZXNyDAsSBEZpbGUYj9gCDA",
+ "theme_tab_background": "$1/Default/Cached Theme Images/theme_tab_background_original",
+ "theme_tab_background_incognito": "$1/Default/Cached Theme Images/theme_tab_background_incognito",
+ "theme_toolbar": "$1/Default/Extensions/mblmlcbknbnfebdfjnolmcapmdofhmme/1.1/i/agxjaHJvbWV0aGVtZXNyDAsSBEZpbGUYnMgCDA",
+ "theme_window_control_background": "$1/Default/Extensions/mblmlcbknbnfebdfjnolmcapmdofhmme/1.1/i/agxjaHJvbWV0aGVtZXNyDAsSBEZpbGUYjNgCDA"
+ },
+ "properties": {
+ "ntp_background_alignment": "top",
+ "ntp_background_repeat": "no-repeat"
+ },
+ "tints": {
+ "buttons": [ 0.6, 0.553, 0.5 ]
+ }
}
},
"profile": {