1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/webui/theme_source.h"
6
7#include "base/memory/ref_counted_memory.h"
8#include "base/message_loop.h"
9#include "chrome/browser/profiles/profile.h"
10#include "chrome/browser/resources_util.h"
11#include "chrome/browser/themes/theme_service.h"
12#include "chrome/browser/themes/theme_service_factory.h"
13#include "chrome/browser/ui/webui/ntp_resource_cache.h"
14#include "chrome/common/url_constants.h"
15#include "content/browser/browser_thread.h"
16#include "googleurl/src/gurl.h"
17#include "ui/base/resource/resource_bundle.h"
18#include "ui/base/theme_provider.h"
19
20// use a resource map rather than hard-coded strings.
21static const char* kNewTabCSSPath = "css/newtab.css";
22static const char* kNewIncognitoTabCSSPath = "css/newincognitotab.css";
23
24static std::string StripQueryParams(const std::string& path) {
25  GURL path_url = GURL(std::string(chrome::kChromeUIScheme) + "://" +
26                       std::string(chrome::kChromeUIThemePath) + "/" + path);
27  return path_url.path().substr(1);  // path() always includes a leading '/'.
28}
29
30////////////////////////////////////////////////////////////////////////////////
31// ThemeSource, public:
32
33ThemeSource::ThemeSource(Profile* profile)
34    : DataSource(chrome::kChromeUIThemePath, MessageLoop::current()),
35      profile_(profile->GetOriginalProfile()) {
36  css_bytes_ = profile_->GetNTPResourceCache()->GetNewTabCSS(
37      profile->IsOffTheRecord());
38}
39
40ThemeSource::~ThemeSource() {
41}
42
43void ThemeSource::StartDataRequest(const std::string& path,
44                                   bool is_incognito,
45                                   int request_id) {
46  // Our path may include cachebuster arguments, so trim them off.
47  std::string uncached_path = StripQueryParams(path);
48
49  if (uncached_path == kNewTabCSSPath ||
50      uncached_path == kNewIncognitoTabCSSPath) {
51    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
52    DCHECK((uncached_path == kNewTabCSSPath && !is_incognito) ||
53           (uncached_path == kNewIncognitoTabCSSPath && is_incognito));
54
55    SendResponse(request_id, css_bytes_);
56    return;
57  } else {
58    int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path);
59    if (resource_id != -1) {
60      SendThemeBitmap(request_id, resource_id);
61      return;
62    }
63  }
64  // We don't have any data to send back.
65  SendResponse(request_id, NULL);
66}
67
68std::string ThemeSource::GetMimeType(const std::string& path) const {
69  std::string uncached_path = StripQueryParams(path);
70
71  if (uncached_path == kNewTabCSSPath ||
72      uncached_path == kNewIncognitoTabCSSPath) {
73    return "text/css";
74  }
75
76  return "image/png";
77}
78
79MessageLoop* ThemeSource::MessageLoopForRequestPath(
80    const std::string& path) const {
81  std::string uncached_path = StripQueryParams(path);
82
83  if (uncached_path == kNewTabCSSPath ||
84      uncached_path == kNewIncognitoTabCSSPath) {
85    // We generated and cached this when we initialized the object.  We don't
86    // have to go back to the UI thread to send the data.
87    return NULL;
88  }
89
90  // If it's not a themeable image, we don't need to go to the UI thread.
91  int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path);
92  if (!ThemeService::IsThemeableImage(resource_id))
93    return NULL;
94
95  return DataSource::MessageLoopForRequestPath(path);
96}
97
98bool ThemeSource::ShouldReplaceExistingSource() const {
99  // We currently get the css_bytes_ in the ThemeSource constructor, so we need
100  // to recreate the source itself when a theme changes.
101  return true;
102}
103
104////////////////////////////////////////////////////////////////////////////////
105// ThemeSource, private:
106
107void ThemeSource::SendThemeBitmap(int request_id, int resource_id) {
108  if (ThemeService::IsThemeableImage(resource_id)) {
109    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
110    ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
111    DCHECK(tp);
112
113    scoped_refptr<RefCountedMemory> image_data(tp->GetRawData(resource_id));
114    SendResponse(request_id, image_data);
115  } else {
116    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
117    const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
118    SendResponse(request_id, rb.LoadDataResourceBytes(resource_id));
119  }
120}
121