Profile shouldn't own BrowserThemeProviders; A ThemeService should and should give back a BTP when presented with a Profile.

This removes all Profile methods that deal with themes. A profile is now just the key that ThemeService maps to a BrowserThemeProvider. Any user of a BrowserThemeProvider asks ThemeService::GetForProfile() instead of the now deleted Profile::GetThemeProvider() method.

Why do this? Because this will drastically reduce coupling. Right now, the Profile knows about pretty much every major object in chrome/browser/. This should allow easier compile time removal of certain systems.

BUG=profile effort
TEST=existing tests

Review URL: http://codereview.chromium.org/6714003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79001 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index 30149aa3..81c0294c 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -59,6 +59,8 @@
 #include "chrome/browser/search_engines/template_url_model.h"
 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
 #include "chrome/browser/tab_contents/link_infobar_delegate.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/translate/translate_infobar_delegate.h"
 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
@@ -3801,7 +3803,7 @@
     DictionaryValue* args,
     IPC::Message* reply_message) {
   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
-  const Extension* theme = browser->profile()->GetTheme();
+  const Extension* theme = ThemeServiceFactory::GetThemeForProfile(profile());
   if (theme) {
     return_value->SetString("name", theme->name());
     return_value->Set("images", theme->GetThemeImages()->DeepCopy());
@@ -5140,7 +5142,7 @@
 }
 
 void TestingAutomationProvider::ResetToDefaultTheme() {
-  profile_->ClearTheme();
+  ThemeServiceFactory::GetForProfile(profile_)->UseDefaultTheme();
 }
 
 void TestingAutomationProvider::WaitForProcessLauncherThreadToGoIdle(
diff --git a/chrome/browser/debugger/devtools_window.cc b/chrome/browser/debugger/devtools_window.cc
index 5e4b3246..0cabc18 100644
--- a/chrome/browser/debugger/devtools_window.cc
+++ b/chrome/browser/debugger/devtools_window.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/tabs/tab_strip_model.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
 #include "chrome/common/bindings_policy.h"
@@ -377,7 +378,7 @@
 }
 
 GURL DevToolsWindow::GetDevToolsUrl() {
-  BrowserThemeProvider* tp = profile_->GetThemeProvider();
+  BrowserThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
   CHECK(tp);
 
   SkColor color_toolbar =
@@ -395,7 +396,7 @@
 }
 
 void DevToolsWindow::UpdateTheme() {
-  BrowserThemeProvider* tp = profile_->GetThemeProvider();
+  BrowserThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
   CHECK(tp);
 
   SkColor color_toolbar =
diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc
index f309429..cfe4925 100644
--- a/chrome/browser/extensions/extension_install_ui.cc
+++ b/chrome/browser/extensions/extension_install_ui.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/tabs/tab_strip_model.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/common/extensions/extension.h"
@@ -103,7 +104,8 @@
       ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {
   // Remember the current theme in case the user presses undo.
   if (profile_) {
-    const Extension* previous_theme = profile_->GetTheme();
+    const Extension* previous_theme =
+        ThemeServiceFactory::GetThemeForProfile(profile_);
     if (previous_theme)
       previous_theme_id_ = previous_theme->id();
 #if defined(TOOLKIT_GTK)
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc
index 05eebdf..f353bb9 100644
--- a/chrome/browser/extensions/extension_install_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/test/ui_test_utils.h"
 #include "content/browser/tab_contents/tab_contents.h"
 
@@ -29,6 +30,10 @@
     delegate->Cancel();
     ASSERT_EQ(0U, tab_contents->infobar_count());
   }
+
+  const Extension* GetTheme() const {
+    return ThemeServiceFactory::GetThemeForProfile(browser()->profile());
+  }
 };
 
 IN_PROC_BROWSER_TEST_F(ExtensionInstallUIBrowserTest,
@@ -36,26 +41,26 @@
   // Install theme once and undo to verify we go back to default theme.
   FilePath theme_crx = PackExtension(test_data_dir_.AppendASCII("theme"));
   ASSERT_TRUE(InstallExtensionWithUI(theme_crx, 1));
-  const Extension* theme = browser()->profile()->GetTheme();
+  const Extension* theme = GetTheme();
   ASSERT_TRUE(theme);
   std::string theme_id = theme->id();
   VerifyThemeInfoBarAndUndoInstall();
-  ASSERT_EQ(NULL, browser()->profile()->GetTheme());
+  ASSERT_EQ(NULL, GetTheme());
 
   // Set the same theme twice and undo to verify we go back to default theme.
   // We set the |expected_change| to zero in these 'InstallExtensionWithUI'
   // calls since the theme has already been installed above and this is an
   // overinstall to set the active theme.
   ASSERT_TRUE(InstallExtensionWithUI(theme_crx, 0));
-  theme = browser()->profile()->GetTheme();
+  theme = GetTheme();
   ASSERT_TRUE(theme);
   ASSERT_EQ(theme_id, theme->id());
   ASSERT_TRUE(InstallExtensionWithUI(theme_crx, 0));
-  theme = browser()->profile()->GetTheme();
+  theme = GetTheme();
   ASSERT_TRUE(theme);
   ASSERT_EQ(theme_id, theme->id());
   VerifyThemeInfoBarAndUndoInstall();
-  ASSERT_EQ(NULL, browser()->profile()->GetTheme());
+  ASSERT_EQ(NULL, GetTheme());
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionInstallUIBrowserTest,
@@ -63,20 +68,20 @@
   // Install first theme.
   FilePath theme_path = test_data_dir_.AppendASCII("theme");
   ASSERT_TRUE(InstallExtensionWithUI(theme_path, 1));
-  const Extension* theme = browser()->profile()->GetTheme();
+  const Extension* theme = GetTheme();
   ASSERT_TRUE(theme);
   std::string theme_id = theme->id();
 
   // Then install second theme.
   FilePath theme_path2 = test_data_dir_.AppendASCII("theme2");
   ASSERT_TRUE(InstallExtensionWithUI(theme_path2, 1));
-  const Extension* theme2 = browser()->profile()->GetTheme();
+  const Extension* theme2 = GetTheme();
   ASSERT_TRUE(theme2);
   EXPECT_FALSE(theme_id == theme2->id());
 
   // Undo second theme will revert to first theme.
   VerifyThemeInfoBarAndUndoInstall();
-  EXPECT_EQ(theme, browser()->profile()->GetTheme());
+  EXPECT_EQ(theme, GetTheme());
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionInstallUIBrowserTest,
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 4b19b42..aebbcad3 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -48,6 +48,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_model.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/webui/shown_sections_handler.h"
 #include "chrome/common/child_process_logging.h"
 #include "chrome/common/chrome_switches.h"
@@ -1350,7 +1351,7 @@
   // defensive; in the future, we may call GarbageCollectExtensions()
   // from somewhere other than Init() (e.g., in a timer).
   if (profile_) {
-    profile_->GetThemeProvider()->RemoveUnusedThemes();
+    ThemeServiceFactory::GetForProfile(profile_)->RemoveUnusedThemes();
   }
 }
 
diff --git a/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc b/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc
index cd2f123a..79f2d641f 100644
--- a/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/gtk_theme_installed_infobar_delegate.cc
@@ -1,10 +1,10 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "chrome/browser/extensions/gtk_theme_installed_infobar_delegate.h"
 
-#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
 
 GtkThemeInstalledInfoBarDelegate::GtkThemeInstalledInfoBarDelegate(
     TabContents* tab_contents,
@@ -17,7 +17,7 @@
 
 bool GtkThemeInstalledInfoBarDelegate::Cancel() {
   if (previous_use_gtk_theme_) {
-    profile()->SetNativeTheme();
+    provider()->SetNativeTheme();
     return true;
   } else {
     return ThemeInstalledInfoBarDelegate::Cancel();
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
index ea27cd9..c76f494 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/common/extensions/extension.h"
 #include "content/browser/tab_contents/tab_contents.h"
 #include "content/common/notification_service.h"
@@ -24,11 +25,12 @@
     const std::string& previous_theme_id)
     : ConfirmInfoBarDelegate(tab_contents),
       profile_(tab_contents->profile()),
+      provider_(ThemeServiceFactory::GetForProfile(profile_)),
       name_(new_theme->name()),
       theme_id_(new_theme->id()),
       previous_theme_id_(previous_theme_id),
       tab_contents_(tab_contents) {
-  profile_->GetThemeProvider()->OnInfobarDisplayed();
+  provider_->OnInfobarDisplayed();
   registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
                  NotificationService::AllSources());
 }
@@ -41,7 +43,7 @@
   // We don't want any notifications while we're running our destructor.
   registrar_.RemoveAll();
 
-  profile_->GetThemeProvider()->OnInfobarDestroyed();
+  provider_->OnInfobarDestroyed();
 }
 
 bool ThemeInstalledInfoBarDelegate::Cancel() {
@@ -51,13 +53,13 @@
       const Extension* previous_theme =
           service->GetExtensionById(previous_theme_id_, true);
       if (previous_theme) {
-        profile_->SetTheme(previous_theme);
+        provider_->SetTheme(previous_theme);
         return true;
       }
     }
   }
 
-  profile_->ClearTheme();
+  provider_->UseDefaultTheme();
   return true;
 }
 
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.h b/chrome/browser/extensions/theme_installed_infobar_delegate.h
index d3eaeb6..1288a55 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.h
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.h
@@ -9,6 +9,7 @@
 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
 #include "content/common/notification_registrar.h"
 
+class BrowserThemeProvider;
 class Extension;
 class SkBitmap;
 class TabContents;
@@ -29,7 +30,7 @@
  protected:
   virtual ~ThemeInstalledInfoBarDelegate();
 
-  Profile* profile() { return profile_; }
+  BrowserThemeProvider* provider() { return provider_; }
 
   // ConfirmInfoBarDelegate:
   virtual bool Cancel();
@@ -49,6 +50,7 @@
                        const NotificationDetails& details);
 
   Profile* profile_;
+  BrowserThemeProvider* provider_;
 
   // Name of theme that's just been installed.
   std::string name_;
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 2902aad5..74c4222f 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -397,30 +397,6 @@
     return file_system_context_.get();
   }
 
-  virtual void InitThemes() {
-    profile_->InitThemes();
-  }
-
-  virtual void SetTheme(const Extension* extension) {
-    profile_->SetTheme(extension);
-  }
-
-  virtual void SetNativeTheme() {
-    profile_->SetNativeTheme();
-  }
-
-  virtual void ClearTheme() {
-    profile_->ClearTheme();
-  }
-
-  virtual const Extension* GetTheme() {
-    return profile_->GetTheme();
-  }
-
-  virtual BrowserThemeProvider* GetThemeProvider() {
-    return profile_->GetThemeProvider();
-  }
-
   virtual URLRequestContextGetter* GetRequestContext() {
     return io_data_.GetMainRequestContextGetter();
   }
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 236e0e5e..35f8e5488 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -315,25 +315,6 @@
   // Returns the BrowserSignin object assigned to this profile.
   virtual BrowserSignin* GetBrowserSignin() = 0;
 
-  // Init our themes system.
-  virtual void InitThemes() = 0;
-
-  // Set the theme to the specified extension.
-  virtual void SetTheme(const Extension* extension) = 0;
-
-  // Set the theme to the machine's native theme.
-  virtual void SetNativeTheme() = 0;
-
-  // Clear the theme and reset it to default.
-  virtual void ClearTheme() = 0;
-
-  // Gets the theme that was last set. Returns NULL if the theme is no longer
-  // installed, if there is no installed theme, or the theme was cleared.
-  virtual const Extension* GetTheme() = 0;
-
-  // Returns or creates the ThemeProvider associated with this profile
-  virtual BrowserThemeProvider* GetThemeProvider() = 0;
-
   // Returns the request context information associated with this profile.  Call
   // this only on the UI thread, since it can send notifications that should
   // happen on the UI thread.
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index e052ecd..28eb99a 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -100,10 +100,6 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "webkit/database/database_tracker.h"
 
-#if defined(TOOLKIT_USES_GTK)
-#include "chrome/browser/ui/gtk/gtk_theme_provider.h"
-#endif
-
 #if defined(OS_WIN)
 #include "chrome/browser/instant/promo_counter.h"
 #include "chrome/browser/password_manager/password_store_win.h"
@@ -256,7 +252,6 @@
       created_web_data_service_(false),
       created_password_store_(false),
       created_download_manager_(false),
-      created_theme_provider_(false),
       start_time_(Time::Now()),
       spellcheck_host_(NULL),
       spellcheck_host_ready_(false),
@@ -283,10 +278,6 @@
   chrome::GetUserCacheDirectory(path_, &base_cache_path_);
   file_util::CreateDirectory(base_cache_path_);
 
-  // Listen for theme installations from our original profile.
-  registrar_.Add(this, NotificationType::THEME_INSTALLED,
-                 Source<Profile>(GetOriginalProfile()));
-
 #if !defined(OS_CHROMEOS)
   // Listen for bookmark model load, to bootstrap the sync service.
   // On CrOS sync service will be initialized after sign in.
@@ -553,9 +544,6 @@
     download_manager_ = NULL;
   }
 
-  // The theme provider provides bitmaps to whoever wants them.
-  theme_provider_.reset();
-
   // Remove pref observers
   pref_change_registrar_.RemoveAll();
 
@@ -1104,48 +1092,6 @@
   return file_system_context_.get();
 }
 
-void ProfileImpl::InitThemes() {
-  if (!created_theme_provider_) {
-#if defined(TOOLKIT_USES_GTK)
-    theme_provider_.reset(new GtkThemeProvider);
-#else
-    theme_provider_.reset(new BrowserThemeProvider);
-#endif
-    theme_provider_->Init(this);
-    created_theme_provider_ = true;
-  }
-}
-
-void ProfileImpl::SetTheme(const Extension* extension) {
-  InitThemes();
-  theme_provider_.get()->SetTheme(extension);
-}
-
-void ProfileImpl::SetNativeTheme() {
-  InitThemes();
-  theme_provider_.get()->SetNativeTheme();
-}
-
-void ProfileImpl::ClearTheme() {
-  InitThemes();
-  theme_provider_.get()->UseDefaultTheme();
-}
-
-const Extension* ProfileImpl::GetTheme() {
-  InitThemes();
-
-  std::string id = theme_provider_.get()->GetThemeID();
-  if (id == BrowserThemeProvider::kDefaultThemeID)
-    return NULL;
-
-  return extensions_service_->GetExtensionById(id, false);
-}
-
-BrowserThemeProvider* ProfileImpl::GetThemeProvider() {
-  InitThemes();
-  return theme_provider_.get();
-}
-
 SessionService* ProfileImpl::GetSessionService() {
   if (!session_service_.get() && !shutdown_session_service_) {
     session_service_ = new SessionService(this);
@@ -1327,10 +1273,6 @@
             clear_local_state_on_exit_);
       }
     }
-  } else if (NotificationType::THEME_INSTALLED == type) {
-    DCHECK_EQ(Source<Profile>(source).ptr(), GetOriginalProfile());
-    const Extension* extension = Details<const Extension>(details).ptr();
-    SetTheme(extension);
   } else if (NotificationType::BOOKMARK_MODEL_LOADED == type) {
     GetProfileSyncService();  // Causes lazy-load if sync is enabled.
     registrar_.Remove(this, NotificationType::BOOKMARK_MODEL_LOADED,
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 9f6914d..4a88d4f 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -79,12 +79,6 @@
   virtual DownloadManager* GetDownloadManager();
   virtual PersonalDataManager* GetPersonalDataManager();
   virtual fileapi::FileSystemContext* GetFileSystemContext();
-  virtual void InitThemes();
-  virtual void SetTheme(const Extension* extension);
-  virtual void SetNativeTheme();
-  virtual void ClearTheme();
-  virtual const Extension* GetTheme();
-  virtual BrowserThemeProvider* GetThemeProvider();
   virtual bool HasCreatedDownloadManager() const;
   virtual URLRequestContextGetter* GetRequestContext();
   virtual URLRequestContextGetter* GetRequestContextForPossibleApp(
@@ -246,7 +240,6 @@
   scoped_refptr<WebDataService> web_data_service_;
   scoped_refptr<PasswordStore> password_store_;
   scoped_refptr<SessionService> session_service_;
-  scoped_ptr<BrowserThemeProvider> theme_provider_;
   scoped_refptr<WebKitContext> webkit_context_;
   scoped_ptr<DesktopNotificationService> desktop_notification_service_;
   scoped_ptr<BackgroundContentsService> background_contents_service_;
@@ -261,7 +254,6 @@
   bool created_web_data_service_;
   bool created_password_store_;
   bool created_download_manager_;
-  bool created_theme_provider_;
   bool clear_local_state_on_exit_;
   // Whether or not the last session exited cleanly. This is set only once.
   bool last_session_exited_cleanly_;
diff --git a/chrome/browser/sync/glue/theme_change_processor.cc b/chrome/browser/sync/glue/theme_change_processor.cc
index 4f4013ee..53b20c7 100644
--- a/chrome/browser/sync/glue/theme_change_processor.cc
+++ b/chrome/browser/sync/glue/theme_change_processor.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/sync/glue/theme_util.h"
 #include "chrome/browser/sync/protocol/theme_specifics.pb.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/common/extensions/extension.h"
 #include "content/common/notification_details.h"
 #include "content/common/notification_source.h"
@@ -45,9 +46,11 @@
   } else {
     extension = Details<const Extension>(details).ptr();
   }
-  std::string current_or_future_theme_id =
-      profile_->GetThemeProvider()->GetThemeID();
-  const Extension* current_theme = profile_->GetTheme();
+  BrowserThemeProvider* theme_provider =
+      ThemeServiceFactory::GetForProfile(profile_);
+  std::string current_or_future_theme_id = theme_provider->GetThemeID();
+  const Extension* current_theme =
+      ThemeServiceFactory::GetThemeForProfile(profile_);
   switch (type.value) {
     case NotificationType::BROWSER_THEME_CHANGED:
       // We pay attention to this notification only when it signifies
@@ -59,7 +62,7 @@
       VLOG(1) << "Got BROWSER_THEME_CHANGED notification for theme "
               << GetThemeId(extension);
       DCHECK_EQ(Source<BrowserThemeProvider>(source).ptr(),
-                profile_->GetThemeProvider());
+                theme_provider);
       if (extension != NULL) {
         DCHECK(extension->is_theme());
         DCHECK_EQ(extension->id(), current_or_future_theme_id);
@@ -202,7 +205,8 @@
              "EXTENSION_UNLOADED";
   notification_registrar_.Add(
       this, NotificationType::BROWSER_THEME_CHANGED,
-      Source<BrowserThemeProvider>(profile_->GetThemeProvider()));
+      Source<BrowserThemeProvider>(
+          ThemeServiceFactory::GetForProfile(profile_)));
   notification_registrar_.Add(
       this, NotificationType::EXTENSION_LOADED,
       Source<Profile>(profile_));
diff --git a/chrome/browser/sync/glue/theme_util.cc b/chrome/browser/sync/glue/theme_util.cc
index 2e91f02..306c9a7 100644
--- a/chrome/browser/sync/glue/theme_util.cc
+++ b/chrome/browser/sync/glue/theme_util.cc
@@ -16,6 +16,8 @@
 #endif
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/protocol/theme_specifics.pb.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "googleurl/src/gurl.h"
@@ -113,7 +115,8 @@
       // Get previous theme info before we set the new theme.
       std::string previous_theme_id;
       {
-        const Extension* current_theme = profile->GetTheme();
+        const Extension* current_theme =
+            ThemeServiceFactory::GetThemeForProfile(profile);
         if (current_theme) {
           DCHECK(current_theme->is_theme());
           previous_theme_id = current_theme->id();
@@ -122,7 +125,7 @@
       bool previous_use_system_theme = UseSystemTheme(profile);
       // An enabled theme extension with the given id was found, so
       // just set the current theme to it.
-      profile->SetTheme(extension);
+      ThemeServiceFactory::GetForProfile(profile)->SetTheme(extension);
       // Pretend the theme was just installed.
       ExtensionInstallUI::ShowThemeInfoBar(
           previous_theme_id, previous_use_system_theme,
@@ -151,17 +154,18 @@
       extension_updater->CheckNow();
     }
   } else if (theme_specifics.use_system_theme_by_default()) {
-    profile->SetNativeTheme();
+    ThemeServiceFactory::GetForProfile(profile)->SetNativeTheme();
   } else {
-    profile->ClearTheme();
+    ThemeServiceFactory::GetForProfile(profile)->UseDefaultTheme();
   }
 }
 
 bool UpdateThemeSpecificsOrSetCurrentThemeIfNecessary(
     Profile* profile, sync_pb::ThemeSpecifics* theme_specifics) {
   if (!theme_specifics->use_custom_theme() &&
-      (profile->GetTheme() || (UseSystemTheme(profile) &&
-                               IsSystemThemeDistinctFromDefaultTheme()))) {
+      (ThemeServiceFactory::GetThemeForProfile(profile) ||
+       (UseSystemTheme(profile) &&
+        IsSystemThemeDistinctFromDefaultTheme()))) {
     GetThemeSpecificsFromCurrentTheme(profile, theme_specifics);
     return true;
   } else {
@@ -174,7 +178,8 @@
     Profile* profile,
     sync_pb::ThemeSpecifics* theme_specifics) {
   DCHECK(profile);
-  const Extension* current_theme = profile->GetTheme();
+  const Extension* current_theme =
+      ThemeServiceFactory::GetThemeForProfile(profile);
   if (current_theme) {
     DCHECK(current_theme->is_theme());
   }
diff --git a/chrome/browser/sync/glue/theme_util_unittest.cc b/chrome/browser/sync/glue/theme_util_unittest.cc
index dfa3ea3..119c4ba 100644
--- a/chrome/browser/sync/glue/theme_util_unittest.cc
+++ b/chrome/browser/sync/glue/theme_util_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -8,6 +8,8 @@
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/protocol/theme_specifics.pb.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/test/testing_profile.h"
@@ -88,30 +90,35 @@
   EXPECT_TRUE(AreThemeSpecificsEqualHelper(a, b, true));
 }
 
-class MockProfile : public TestingProfile {
+class MockBrowserThemeProvider : public BrowserThemeProvider {
  public:
   MOCK_METHOD0(SetNativeTheme, void());
-  MOCK_METHOD0(ClearTheme, void());
-  MOCK_METHOD0(GetTheme, Extension*());
+  MOCK_METHOD0(UseDefaultTheme, void());
+  MOCK_CONST_METHOD0(GetThemeID, std::string());
 };
 
 TEST_F(ThemeUtilTest, SetCurrentThemeDefaultTheme) {
   sync_pb::ThemeSpecifics theme_specifics;
+  TestingProfile profile;
+  MockBrowserThemeProvider* mock_provider = new MockBrowserThemeProvider;
+  ThemeServiceFactory::ForceAssociationBetween(&profile, mock_provider);
 
-  MockProfile mock_profile;
-  EXPECT_CALL(mock_profile, ClearTheme()).Times(1);
+  EXPECT_CALL(*mock_provider, UseDefaultTheme()).Times(1);
 
-  SetCurrentThemeFromThemeSpecifics(theme_specifics, &mock_profile);
+  SetCurrentThemeFromThemeSpecifics(theme_specifics, &profile);
 }
 
 TEST_F(ThemeUtilTest, SetCurrentThemeSystemTheme) {
   sync_pb::ThemeSpecifics theme_specifics;
   theme_specifics.set_use_system_theme_by_default(true);
 
-  MockProfile mock_profile;
-  EXPECT_CALL(mock_profile, SetNativeTheme()).Times(1);
+  TestingProfile profile;
+  MockBrowserThemeProvider* mock_provider = new MockBrowserThemeProvider;
+  ThemeServiceFactory::ForceAssociationBetween(&profile, mock_provider);
 
-  SetCurrentThemeFromThemeSpecifics(theme_specifics, &mock_profile);
+  EXPECT_CALL(*mock_provider, SetNativeTheme()).Times(1);
+
+  SetCurrentThemeFromThemeSpecifics(theme_specifics, &profile);
 }
 
 // TODO(akalin): Make ExtensionService/ExtensionUpdater testable
@@ -205,15 +212,18 @@
 }
 
 TEST_F(ThemeUtilTest, SetCurrentThemeIfNecessaryDefaultThemeNotNecessary) {
-  MockProfile mock_profile;
-  Extension* extension = NULL;
-  EXPECT_CALL(mock_profile, GetTheme()).WillOnce(Return(extension));
+  TestingProfile profile;
+  MockBrowserThemeProvider* mock_provider = new MockBrowserThemeProvider;
+  ThemeServiceFactory::ForceAssociationBetween(&profile, mock_provider);
+
+  EXPECT_CALL(*mock_provider, GetThemeID()).WillRepeatedly(Return(
+      BrowserThemeProvider::kDefaultThemeID));
 
   // TODO(akalin): Mock out call to GetPrefs() under TOOLKIT_USES_GTK.
 
   sync_pb::ThemeSpecifics theme_specifics;
   SetCurrentThemeFromThemeSpecificsIfNecessary(theme_specifics,
-                                               &mock_profile);
+                                               &profile);
 }
 
 }  // namespace
diff --git a/chrome/browser/themes/browser_theme_provider.h b/chrome/browser/themes/browser_theme_provider.h
index fe65a7d..92a5c57 100644
--- a/chrome/browser/themes/browser_theme_provider.h
+++ b/chrome/browser/themes/browser_theme_provider.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -171,7 +171,7 @@
 
   // Gets the id of the last installed theme. (The theme may have been further
   // locally customized.)
-  std::string GetThemeID() const;
+  virtual std::string GetThemeID() const;
 
   // This class needs to keep track of the number of theme infobars so that we
   // clean up unused themes.
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
new file mode 100644
index 0000000..eae2b76a
--- /dev/null
+++ b/chrome/browser/themes/theme_service.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/themes/theme_service.h"
+
+#include "base/logging.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/themes/browser_theme_provider.h"
+#include "content/common/notification_service.h"
+
+#if defined(TOOLKIT_USES_GTK)
+#include "chrome/browser/ui/gtk/gtk_theme_provider.h"
+#endif
+
+// static
+BrowserThemeProvider* ThemeServiceFactory::GetForProfile(Profile* top_profile) {
+  // We may be asked for the Theme of an incognito profile. Make sure we're
+  // operating on the real profile.
+  Profile* profile = top_profile->GetOriginalProfile();
+
+  ThemeServiceFactory* service = GetInstance();
+
+  std::map<Profile*, BrowserThemeProvider*>::const_iterator it =
+      service->mapping_.find(profile);
+  if (it != service->mapping_.end())
+    return it->second;
+
+  BrowserThemeProvider* provider = NULL;
+#if defined(TOOLKIT_USES_GTK)
+  provider = new GtkThemeProvider;
+#else
+  provider = new BrowserThemeProvider;
+#endif
+  provider->Init(profile);
+
+  service->Associate(profile, provider);
+  return provider;
+}
+
+const Extension* ThemeServiceFactory::GetThemeForProfile(Profile* profile) {
+  std::string id = GetForProfile(profile)->GetThemeID();
+  if (id == BrowserThemeProvider::kDefaultThemeID)
+    return NULL;
+
+  return profile->GetExtensionService()->GetExtensionById(id, false);
+}
+
+void ThemeServiceFactory::ForceAssociationBetween(Profile* top_profile,
+                                           BrowserThemeProvider* provider) {
+  ThemeServiceFactory* service = GetInstance();
+  Profile* profile = top_profile->GetOriginalProfile();
+
+  service->Associate(profile, provider);
+}
+
+ThemeServiceFactory* ThemeServiceFactory::GetInstance() {
+  return Singleton<ThemeServiceFactory>::get();
+}
+
+ThemeServiceFactory::ThemeServiceFactory() {}
+
+ThemeServiceFactory::~ThemeServiceFactory() {
+  DCHECK(mapping_.empty());
+}
+
+void ThemeServiceFactory::Associate(Profile* profile,
+                             BrowserThemeProvider* provider) {
+  DCHECK(mapping_.find(profile) == mapping_.end());
+  mapping_.insert(std::make_pair(profile, provider));
+
+  registrar_.Add(this,
+                 NotificationType::PROFILE_DESTROYED,
+                 Source<Profile>(profile));
+  registrar_.Add(this,
+                 NotificationType::THEME_INSTALLED,
+                 Source<Profile>(profile));
+}
+
+void ThemeServiceFactory::Observe(NotificationType type,
+                           const NotificationSource& source,
+                           const NotificationDetails& details) {
+  std::map<Profile*, BrowserThemeProvider*>::iterator it =
+      mapping_.find(Source<Profile>(source).ptr());
+  DCHECK(it != mapping_.end());
+
+  if (NotificationType::PROFILE_DESTROYED == type) {
+    delete it->second;
+    mapping_.erase(it);
+
+    // Remove ourselves from listening to all notifications because the source
+    // profile has been deleted. We have to do this because several unit tests
+    // are set up so a Profile is on the same place on the stack multiple
+    // times, so while they are different instances, they have the same
+    // addresses.
+    registrar_.Remove(this,
+                      NotificationType::PROFILE_DESTROYED,
+                      source);
+    registrar_.Remove(this,
+                      NotificationType::THEME_INSTALLED,
+                      source);
+  } else if (NotificationType::THEME_INSTALLED == type) {
+    const Extension* extension = Details<const Extension>(details).ptr();
+    it->second->SetTheme(extension);
+  } else {
+    NOTREACHED();
+  }
+}
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h
new file mode 100644
index 0000000..44abcc2
--- /dev/null
+++ b/chrome/browser/themes/theme_service.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_THEMES_THEME_SERVICE_H_
+#define CHROME_BROWSER_THEMES_THEME_SERVICE_H_
+
+#include <map>
+
+#include "base/singleton.h"
+#include "content/common/notification_observer.h"
+#include "content/common/notification_registrar.h"
+
+class BrowserThemeProvider;
+class Extension;
+class Profile;
+
+// Singleton that owns all BrowserThemeProviders and associates them with
+// Profiles. Listens for the Profile's destruction notification and cleans up
+// the associated BrowserThemeProvider.
+class ThemeServiceFactory : public NotificationObserver {
+ public:
+  // Returns the BrowserThemeProvider that provides theming resources for
+  // |profile|. Note that even if a Profile doesn't have a theme installed, it
+  // still needs a BrowserThemeProvider to hand back the default theme images.
+  static BrowserThemeProvider* GetForProfile(Profile* profile);
+
+  // Returns the Extension that implements the theme associated with
+  // |profile|. Returns NULL if the theme is no longer installed, if there is
+  // no installed theme, or the theme was cleared.
+  static const Extension* GetThemeForProfile(Profile* profile);
+
+  // Forces an association between |profile| and |provider|. Used in unit tests
+  // where we need to mock BrowserThemeProvider.
+  static void ForceAssociationBetween(Profile* profile,
+                                      BrowserThemeProvider* provider);
+
+  static ThemeServiceFactory* GetInstance();
+
+ private:
+  friend struct DefaultSingletonTraits<ThemeServiceFactory>;
+
+  ThemeServiceFactory();
+  ~ThemeServiceFactory();
+
+  // Maps |profile| to |provider| and listens for notifications relating to
+  // either.
+  void Associate(Profile* profile, BrowserThemeProvider* provider);
+
+  // NotificationObserver:
+  virtual void Observe(NotificationType type,
+                       const NotificationSource& source,
+                       const NotificationDetails& details);
+
+  NotificationRegistrar registrar_;
+  std::map<Profile*, BrowserThemeProvider*> mapping_;
+};
+
+#endif  // CHROME_BROWSER_THEMES_THEME_SERVICE_H_
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
index 787e8fc..594a8bf 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
@@ -15,6 +15,7 @@
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/profiles/profile.h"
 #import "chrome/browser/themes/browser_theme_provider.h"
+#import "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #import "chrome/browser/ui/cocoa/background_gradient_view.h"
@@ -2065,7 +2066,7 @@
 }
 
 - (ui::ThemeProvider*)themeProvider {
-  return browser_->profile()->GetThemeProvider();
+  return ThemeServiceFactory::GetForProfile(browser_->profile());
 }
 
 #pragma mark BookmarkButtonDelegate Protocol
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index c851c17..f01a8830 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -20,6 +20,7 @@
 #include "chrome/browser/tab_contents/tab_contents_view_mac.h"
 #include "chrome/browser/tabs/tab_strip_model.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #import "chrome/browser/ui/cocoa/background_gradient_view.h"
@@ -1525,7 +1526,7 @@
 }
 
 - (ui::ThemeProvider*)themeProvider {
-  return browser_->profile()->GetThemeProvider();
+  return ThemeServiceFactory::GetForProfile(browser_->profile());
 }
 
 - (ThemedWindowStyle)themedWindowStyle {
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
index 26d00fc..2c82d67 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -10,6 +10,7 @@
 #include "chrome/browser/download/download_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/browser.h"
 #import "chrome/browser/ui/cocoa/animatable_view.h"
 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
@@ -163,7 +164,7 @@
 
   if (bridge_.get() && bridge_->browser() && bridge_->browser()->profile()) {
     ui::ThemeProvider* provider =
-        bridge_->browser()->profile()->GetThemeProvider();
+        ThemeServiceFactory::GetForProfile(bridge_->browser()->profile());
 
     color =
         provider->GetNSColor(BrowserThemeProvider::COLOR_BOOKMARK_TEXT, false);
diff --git a/chrome/browser/ui/gtk/gtk_theme_provider.cc b/chrome/browser/ui/gtk/gtk_theme_provider.cc
index 88394db..72475153 100644
--- a/chrome/browser/ui/gtk/gtk_theme_provider.cc
+++ b/chrome/browser/ui/gtk/gtk_theme_provider.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/metrics/user_metrics.h"
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/gtk/cairo_cached_surface.h"
 #include "chrome/browser/ui/gtk/chrome_gtk_frame.h"
 #include "chrome/browser/ui/gtk/gtk_chrome_button.h"
@@ -247,7 +248,8 @@
 
 // static
 GtkThemeProvider* GtkThemeProvider::GetFrom(Profile* profile) {
-  return static_cast<GtkThemeProvider*>(profile->GetThemeProvider());
+  return static_cast<GtkThemeProvider*>(
+      ThemeServiceFactory::GetForProfile(profile));
 }
 
 GtkThemeProvider::GtkThemeProvider()
diff --git a/chrome/browser/ui/gtk/gtk_theme_provider_unittest.cc b/chrome/browser/ui/gtk/gtk_theme_provider_unittest.cc
index 30ad5ff..28d2fabb 100644
--- a/chrome/browser/ui/gtk/gtk_theme_provider_unittest.cc
+++ b/chrome/browser/ui/gtk/gtk_theme_provider_unittest.cc
@@ -32,7 +32,6 @@
   }
 
   void BuildProvider() {
-    profile_.InitThemes();
     provider_ = GtkThemeProvider::GetFrom(&profile_);
   }
 
diff --git a/chrome/browser/ui/gtk/tabs/dragged_tab_gtk.cc b/chrome/browser/ui/gtk/tabs/dragged_tab_gtk.cc
index 9b50a43..a557fe39 100644
--- a/chrome/browser/ui/gtk/tabs/dragged_tab_gtk.cc
+++ b/chrome/browser/ui/gtk/tabs/dragged_tab_gtk.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/tabs/tab_strip_model.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/gtk/gtk_util.h"
 #include "chrome/browser/ui/gtk/tabs/tab_renderer_gtk.h"
 #include "content/browser/renderer_host/backing_store_x.h"
@@ -48,7 +49,8 @@
                              const gfx::Size& contents_size,
                              bool mini)
     : data_source_(datasource),
-      renderer_(new TabRendererGtk(datasource->profile()->GetThemeProvider())),
+      renderer_(new TabRendererGtk(ThemeServiceFactory::GetForProfile(
+          datasource->profile()))),
       attached_(false),
       mouse_tab_offset_(mouse_tab_offset),
       attached_tab_size_(TabRendererGtk::GetMinimumSelectedSize()),
diff --git a/chrome/browser/ui/views/frame/browser_frame_gtk.cc b/chrome/browser/ui/views/frame/browser_frame_gtk.cc
index c56e0fc..a742cc88 100644
--- a/chrome/browser/ui/views/frame/browser_frame_gtk.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_gtk.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/status_bubble.h"
 #include "chrome/browser/ui/views/frame/app_panel_browser_frame_view.h"
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
@@ -92,7 +93,8 @@
 // BrowserFrameGtk, WindowGtk overrides :
 
 ThemeProvider* BrowserFrameGtk::GetThemeProvider() const {
-  return browser_view_->browser()->profile()->GetThemeProvider();
+  return ThemeServiceFactory::GetForProfile(
+      browser_view_->browser()->profile());
 }
 
 void BrowserFrameGtk::SetInitialFocus() {
diff --git a/chrome/browser/ui/views/frame/browser_frame_win.cc b/chrome/browser/ui/views/frame/browser_frame_win.cc
index 831a9c34..2bb3e75 100644
--- a/chrome/browser/ui/views/frame/browser_frame_win.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_win.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/browser_list.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/glass_browser_frame_view.h"
@@ -133,7 +134,8 @@
 }
 
 ThemeProvider* BrowserFrameWin::GetThemeProvider() const {
-  return browser_view_->browser()->profile()->GetThemeProvider();
+  return ThemeServiceFactory::GetForProfile(
+      browser_view_->browser()->profile());
 }
 
 void BrowserFrameWin::OnScreenReaderDetected() {
diff --git a/chrome/browser/ui/views/theme_background.cc b/chrome/browser/ui/views/theme_background.cc
index dabd9ae..e3eb6655 100644
--- a/chrome/browser/ui/views/theme_background.cc
+++ b/chrome/browser/ui/views/theme_background.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "grit/app_resources.h"
 #include "grit/generated_resources.h"
@@ -30,7 +31,8 @@
       background = rb.GetBitmapNamed(IDR_THEME_FRAME_INACTIVE);
   } else {
     Profile* profile = browser_view_->browser()->profile();
-    ui::ThemeProvider* theme = profile->GetThemeProvider();
+    ui::ThemeProvider* theme = ThemeServiceFactory::GetForProfile(profile);
+
     if (browser_view_->IsActive()) {
       background = theme->GetBitmapNamed(
           profile->IsOffTheRecord() ?
diff --git a/chrome/browser/ui/webui/new_tab_ui.cc b/chrome/browser/ui/webui/new_tab_ui.cc
index 7beaf3c..9389ab6 100644
--- a/chrome/browser/ui/webui/new_tab_ui.cc
+++ b/chrome/browser/ui/webui/new_tab_ui.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/sessions/tab_restore_service_observer.h"
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/webui/app_launcher_handler.h"
 #include "chrome/browser/ui/webui/foreign_session_handler.h"
@@ -396,7 +397,7 @@
       InitializeCSSCaches();
       ListValue args;
       args.Append(Value::CreateStringValue(
-          GetProfile()->GetThemeProvider()->HasCustomImage(
+          ThemeServiceFactory::GetForProfile(GetProfile())->HasCustomImage(
               IDR_THEME_NTP_ATTRIBUTION) ?
           "true" : "false"));
       CallJavascriptFunction("themeChanged", args);
diff --git a/chrome/browser/ui/webui/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp_resource_cache.cc
index 0afa746..e634668 100644
--- a/chrome/browser/ui/webui/ntp_resource_cache.cc
+++ b/chrome/browser/ui/webui/ntp_resource_cache.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/prefs/pref_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
 #include "chrome/browser/ui/webui/shown_sections_handler.h"
 #include "chrome/browser/web_resource/promo_resource_service.h"
@@ -264,7 +265,8 @@
       profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar) ?
       "true" : "false");
   localized_strings.SetString("hasattribution",
-      profile_->GetThemeProvider()->HasCustomImage(IDR_THEME_NTP_ATTRIBUTION) ?
+      ThemeServiceFactory::GetForProfile(profile_)->HasCustomImage(
+          IDR_THEME_NTP_ATTRIBUTION) ?
       "true" : "false");
   localized_strings.SetString("apps", apps);
   localized_strings.SetString("title", title);
@@ -432,7 +434,7 @@
 }
 
 void NTPResourceCache::CreateNewTabIncognitoCSS() {
-  ui::ThemeProvider* tp = profile_->GetThemeProvider();
+  ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
   DCHECK(tp);
 
   // Get our theme colors
@@ -468,7 +470,7 @@
 }
 
 void NTPResourceCache::CreateNewTabCSS() {
-  ui::ThemeProvider* tp = profile_->GetThemeProvider();
+  ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
   DCHECK(tp);
 
   // Get our theme colors
diff --git a/chrome/browser/ui/webui/options/personal_options_handler.cc b/chrome/browser/ui/webui/options/personal_options_handler.cc
index 5680af6..c554201 100644
--- a/chrome/browser/ui/webui/options/personal_options_handler.cc
+++ b/chrome/browser/ui/webui/options/personal_options_handler.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/sync/sync_setup_flow.h"
 #include "chrome/browser/sync/sync_ui_util.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/options/options_page_base.h"
 #include "chrome/browser/ui/options/options_window.h"
 #include "chrome/browser/ui/webui/options/options_managed_banner_handler.h"
@@ -336,8 +337,7 @@
   web_ui_->CallJavascriptFunction(
       "options.PersonalOptions.setGtkThemeButtonEnabled", gtk_enabled);
 #else
-  BrowserThemeProvider* provider =
-      reinterpret_cast<BrowserThemeProvider*>(profile->GetThemeProvider());
+  BrowserThemeProvider* provider = ThemeServiceFactory::GetForProfile(profile);
   bool is_gtk_theme = false;
 #endif
 
@@ -418,13 +418,13 @@
 
 void PersonalOptionsHandler::ThemesReset(const ListValue* args) {
   UserMetricsRecordAction(UserMetricsAction("Options_ThemesReset"));
-  web_ui_->GetProfile()->ClearTheme();
+  ThemeServiceFactory::GetForProfile(web_ui_->GetProfile())->UseDefaultTheme();
 }
 
 #if defined(TOOLKIT_GTK)
 void PersonalOptionsHandler::ThemesSetGTK(const ListValue* args) {
   UserMetricsRecordAction(UserMetricsAction("Options_GtkThemeSet"));
-  web_ui_->GetProfile()->SetNativeTheme();
+  ThemeServiceFactory::GetForProfile(web_ui_->GetProfile())->SetNativeTheme();
 }
 #endif
 
diff --git a/chrome/browser/ui/webui/theme_source.cc b/chrome/browser/ui/webui/theme_source.cc
index 9c87ce9f..3c686e7 100644
--- a/chrome/browser/ui/webui/theme_source.cc
+++ b/chrome/browser/ui/webui/theme_source.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/resources_util.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/ui/webui/ntp_resource_cache.h"
 #include "chrome/common/url_constants.h"
 #include "content/browser/browser_thread.h"
@@ -106,7 +107,7 @@
 void ThemeSource::SendThemeBitmap(int request_id, int resource_id) {
   if (BrowserThemeProvider::IsThemeableImage(resource_id)) {
     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-    ui::ThemeProvider* tp = profile_->GetThemeProvider();
+    ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
     DCHECK(tp);
 
     scoped_refptr<RefCountedMemory> image_data(tp->GetRawData(resource_id));
diff --git a/chrome/browser/ui/webui/theme_source_unittest.cc b/chrome/browser/ui/webui/theme_source_unittest.cc
index 959decda..59511c3 100644
--- a/chrome/browser/ui/webui/theme_source_unittest.cc
+++ b/chrome/browser/ui/webui/theme_source_unittest.cc
@@ -42,7 +42,6 @@
  private:
   virtual void SetUp() {
     profile_.reset(new TestingProfile());
-    profile_->InitThemes();
     theme_source_ = new MockThemeSource(profile_.get());
   }
 
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 21789e6..2ea19f0 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2025,6 +2025,8 @@
         'browser/themes/browser_theme_provider.h',
         'browser/themes/browser_theme_provider_gtk.cc',
         'browser/themes/browser_theme_provider_mac.mm',
+        'browser/themes/theme_service.cc',
+        'browser/themes/theme_service.h',
         'browser/translate/languages_menu_model.cc',
         'browser/translate/languages_menu_model.h',
         'browser/translate/options_menu_model.cc',
diff --git a/chrome/test/live_sync/live_themes_sync_test.cc b/chrome/test/live_sync/live_themes_sync_test.cc
index de7d7c3..3c653599 100644
--- a/chrome/test/live_sync/live_themes_sync_test.cc
+++ b/chrome/test/live_sync/live_themes_sync_test.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -10,6 +10,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/browser_theme_provider.h"
+#include "chrome/browser/themes/theme_service.h"
 #include "chrome/common/extensions/extension.h"
 
 LiveThemesSyncTest::LiveThemesSyncTest(TestType test_type)
@@ -23,15 +24,22 @@
   InstallExtension(profile, theme);
 }
 
+void LiveThemesSyncTest::SetNativeTheme(Profile* profile) {
+  ThemeServiceFactory::GetForProfile(profile)->SetNativeTheme();
+}
+
+void LiveThemesSyncTest::UseDefaultTheme(Profile* profile) {
+  ThemeServiceFactory::GetForProfile(profile)->UseDefaultTheme();
+}
+
 const Extension* LiveThemesSyncTest::GetCustomTheme(
     Profile* profile) {
-  return profile->GetTheme();
+  return ThemeServiceFactory::GetThemeForProfile(profile);
 }
 
 bool LiveThemesSyncTest::UsingDefaultTheme(Profile* profile) {
-  return
-      !profile->GetTheme() &&
-      profile->GetThemeProvider()->UsingDefaultTheme();
+  return !ThemeServiceFactory::GetThemeForProfile(profile) &&
+      ThemeServiceFactory::GetForProfile(profile)->UsingDefaultTheme();
 }
 
 bool LiveThemesSyncTest::UsingNativeTheme(Profile* profile) {
@@ -44,10 +52,9 @@
   // Return true if we're not using a custom theme and we don't make a
   // distinction between the default and the system theme, or we do
   // and we're not using the default theme.
-  return
-      !profile->GetTheme() &&
+  return !ThemeServiceFactory::GetThemeForProfile(profile) &&
       (!kHasDistinctNativeTheme ||
-       !profile->GetThemeProvider()->UsingDefaultTheme());
+       !ThemeServiceFactory::GetForProfile(profile)->UsingDefaultTheme());
 }
 
 bool LiveThemesSyncTest::ExtensionIsPendingInstall(
diff --git a/chrome/test/live_sync/live_themes_sync_test.h b/chrome/test/live_sync/live_themes_sync_test.h
index c98e3e4..ad960b2 100644
--- a/chrome/test/live_sync/live_themes_sync_test.h
+++ b/chrome/test/live_sync/live_themes_sync_test.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -27,6 +27,12 @@
   // given theme extension.
   static void SetTheme(Profile* profile, scoped_refptr<Extension> theme);
 
+  // Sets |profile| so that it uses the native theme.
+  void SetNativeTheme(Profile* profile);
+
+  // Sets |profile| to the default theme.
+  void UseDefaultTheme(Profile* profile);
+
   // Gets the custom theme of the given profile, or NULL if the given
   // profile doesn't have one.
   const Extension* GetCustomTheme(Profile* profile) WARN_UNUSED_RESULT;
diff --git a/chrome/test/live_sync/single_client_live_themes_sync_test.cc b/chrome/test/live_sync/single_client_live_themes_sync_test.cc
index c901947..8ae2c3b 100644
--- a/chrome/test/live_sync/single_client_live_themes_sync_test.cc
+++ b/chrome/test/live_sync/single_client_live_themes_sync_test.cc
@@ -50,8 +50,8 @@
   ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion(
       "Waiting for custom themes change."));
 
-  GetProfile(0)->SetNativeTheme();
-  verifier()->SetNativeTheme();
+  SetNativeTheme(GetProfile(0));
+  SetNativeTheme(verifier());
   ASSERT_TRUE(UsingNativeTheme(GetProfile(0)));
   ASSERT_TRUE(UsingNativeTheme(verifier()));
 
@@ -73,8 +73,8 @@
   ASSERT_TRUE(GetClient(0)->AwaitSyncCycleCompletion(
       "Waiting for custom themes change."));
 
-  GetProfile(0)->ClearTheme();
-  verifier()->ClearTheme();
+  UseDefaultTheme(GetProfile(0));
+  UseDefaultTheme(verifier());
   ASSERT_TRUE(UsingDefaultTheme(GetProfile(0)));
   ASSERT_TRUE(UsingDefaultTheme(verifier()));
 
diff --git a/chrome/test/live_sync/two_client_live_themes_sync_test.cc b/chrome/test/live_sync/two_client_live_themes_sync_test.cc
index 29ba596..da5545d 100644
--- a/chrome/test/live_sync/two_client_live_themes_sync_test.cc
+++ b/chrome/test/live_sync/two_client_live_themes_sync_test.cc
@@ -53,8 +53,8 @@
 
   ASSERT_TRUE(AwaitQuiescence());
 
-  GetProfile(0)->SetNativeTheme();
-  verifier()->SetNativeTheme();
+  SetNativeTheme(GetProfile(0));
+  SetNativeTheme(verifier());
   ASSERT_TRUE(UsingNativeTheme(GetProfile(0)));
   ASSERT_FALSE(UsingNativeTheme(GetProfile(1)));
   ASSERT_TRUE(UsingNativeTheme(verifier()));
@@ -75,8 +75,8 @@
 
   ASSERT_TRUE(AwaitQuiescence());
 
-  GetProfile(0)->ClearTheme();
-  verifier()->ClearTheme();
+  UseDefaultTheme(GetProfile(0));
+  UseDefaultTheme(verifier());
   ASSERT_TRUE(UsingDefaultTheme(GetProfile(0)));
   ASSERT_FALSE(UsingDefaultTheme(GetProfile(1)));
   ASSERT_TRUE(UsingDefaultTheme(verifier()));
@@ -91,8 +91,8 @@
 IN_PROC_BROWSER_TEST_F(TwoClientLiveThemesSyncTest, NativeDefaultRace) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
-  GetProfile(0)->SetNativeTheme();
-  GetProfile(1)->ClearTheme();
+  SetNativeTheme(GetProfile(0));
+  UseDefaultTheme(GetProfile(1));
   ASSERT_TRUE(UsingNativeTheme(GetProfile(0)));
   ASSERT_TRUE(UsingDefaultTheme(GetProfile(1)));
 
@@ -111,7 +111,7 @@
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   SetTheme(GetProfile(0), GetTheme(0));
-  GetProfile(1)->SetNativeTheme();
+  SetNativeTheme(GetProfile(1));
   ASSERT_EQ(GetTheme(0), GetCustomTheme(GetProfile(0)));
   ASSERT_TRUE(UsingNativeTheme(GetProfile(1)));
 
@@ -128,7 +128,7 @@
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   SetTheme(GetProfile(0), GetTheme(0));
-  GetProfile(1)->ClearTheme();
+  UseDefaultTheme(GetProfile(1));
   ASSERT_EQ(GetTheme(0), GetCustomTheme(GetProfile(0)));
   ASSERT_TRUE(UsingDefaultTheme(GetProfile(1)));
 
diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc
index a3483370..26e452c 100644
--- a/chrome/test/testing_profile.cc
+++ b/chrome/test/testing_profile.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/search_engines/template_url_model.h"
 #include "chrome/browser/sessions/session_service.h"
 #include "chrome/browser/sync/profile_sync_service_mock.h"
-#include "chrome/browser/themes/browser_theme_provider.h"
 #include "chrome/browser/ui/find_bar/find_bar_state.h"
 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
 #include "chrome/browser/ui/webui/ntp_resource_cache.h"
@@ -54,10 +53,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "webkit/database/database_tracker.h"
 
-#if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS)
-#include "chrome/browser/ui/gtk/gtk_theme_provider.h"
-#endif
-
 using base::Time;
 using testing::NiceMock;
 using testing::Return;
@@ -149,7 +144,6 @@
 TestingProfile::TestingProfile()
     : start_time_(Time::Now()),
       testing_prefs_(NULL),
-      created_theme_provider_(false),
       has_history_service_(false),
       off_the_record_(false),
       last_session_exited_cleanly_(true) {
@@ -330,9 +324,7 @@
 }
 
 void TestingProfile::UseThemeProvider(BrowserThemeProvider* theme_provider) {
-  theme_provider->Init(this);
-  created_theme_provider_ = true;
-  theme_provider_.reset(theme_provider);
+  NOTREACHED() << "This needs to go away for a different testing interface.";
 }
 
 ExtensionService* TestingProfile::CreateExtensionService(
@@ -482,27 +474,6 @@
   return NULL;
 }
 
-void TestingProfile::InitThemes() {
-  if (!created_theme_provider_) {
-#if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS)
-    theme_provider_.reset(new GtkThemeProvider);
-#else
-    theme_provider_.reset(new BrowserThemeProvider);
-#endif
-    theme_provider_->Init(this);
-    created_theme_provider_ = true;
-  }
-}
-
-const Extension* TestingProfile::GetTheme() {
-  return NULL;
-}
-
-BrowserThemeProvider* TestingProfile::GetThemeProvider() {
-  InitThemes();
-  return theme_provider_.get();
-}
-
 void TestingProfile::SetPrefService(PrefService* prefs) {
   DCHECK(!prefs_.get());
   prefs_.reset(prefs);
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 7c3ae2bb..befc5a6 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -185,12 +185,6 @@
   virtual fileapi::FileSystemContext* GetFileSystemContext();
   virtual BrowserSignin* GetBrowserSignin();
   virtual bool HasCreatedDownloadManager() const;
-  virtual void InitThemes();
-  virtual void SetTheme(const Extension* extension) {}
-  virtual void SetNativeTheme() {}
-  virtual void ClearTheme() {}
-  virtual const Extension* GetTheme();
-  virtual BrowserThemeProvider* GetThemeProvider();
 
   // Returns a testing ContextGetter (if one has been created via
   // CreateRequestContext) or NULL. This is not done on-demand for two reasons:
@@ -345,10 +339,6 @@
   // The SessionService. Defaults to NULL, but can be set using the setter.
   scoped_refptr<SessionService> session_service_;
 
-  // The theme provider. Created lazily by GetThemeProvider()/InitThemes().
-  scoped_ptr<BrowserThemeProvider> theme_provider_;
-  bool created_theme_provider_;
-
   // Internally, this is a TestURLRequestContextGetter that creates a dummy
   // request context. Currently, only the CookieMonster is hooked up.
   scoped_refptr<URLRequestContextGetter> request_context_;