1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
// Copyright (c) 2012 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/ui/webui/theme_source.h"
#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/resources_util.h"
#include "chrome/browser/search/instant_io_context.h"
#include "chrome/browser/themes/browser_theme_pack.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/webui/ntp/ntp_resource_cache.h"
#include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request.h"
#include "ui/base/layout.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "url/gurl.h"
using content::BrowserThread;
namespace {
std::string GetThemePath() {
return std::string(content::kChromeUIScheme) + "://" +
std::string(chrome::kChromeUIThemePath) + "/";
}
// use a resource map rather than hard-coded strings.
static const char* kNewTabCSSPath = "css/new_tab_theme.css";
static const char* kNewIncognitoTabCSSPath = "css/incognito_new_tab_theme.css";
} // namespace
////////////////////////////////////////////////////////////////////////////////
// ThemeSource, public:
ThemeSource::ThemeSource(Profile* profile)
: profile_(profile->GetOriginalProfile()) {
NTPResourceCache::WindowType win_type = NTPResourceCache::GetWindowType(
profile_, NULL);
css_bytes_ =
NTPResourceCacheFactory::GetForProfile(profile)->GetNewTabCSS(win_type);
}
ThemeSource::~ThemeSource() {
}
std::string ThemeSource::GetSource() const {
return chrome::kChromeUIThemePath;
}
void ThemeSource::StartDataRequest(
const std::string& path,
int render_process_id,
int render_frame_id,
const content::URLDataSource::GotDataCallback& callback) {
// Default scale factor if not specified.
float scale_factor = 1.0f;
std::string uncached_path;
webui::ParsePathAndScale(GURL(GetThemePath() + path),
&uncached_path,
&scale_factor);
if (uncached_path == kNewTabCSSPath ||
uncached_path == kNewIncognitoTabCSSPath) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
callback.Run(css_bytes_.get());
return;
}
int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path);
if (resource_id != -1) {
if (GetMimeType(path) == "image/png")
SendThemeImage(callback, resource_id, scale_factor);
else
SendThemeBitmap(callback, resource_id, scale_factor);
return;
}
// We don't have any data to send back.
callback.Run(NULL);
}
std::string ThemeSource::GetMimeType(const std::string& path) const {
std::string uncached_path;
webui::ParsePathAndScale(GURL(GetThemePath() + path), &uncached_path, NULL);
if (uncached_path == kNewTabCSSPath ||
uncached_path == kNewIncognitoTabCSSPath) {
return "text/css";
}
return "image/png";
}
base::MessageLoop* ThemeSource::MessageLoopForRequestPath(
const std::string& path) const {
std::string uncached_path;
webui::ParsePathAndScale(GURL(GetThemePath() + path), &uncached_path, NULL);
if (uncached_path == kNewTabCSSPath ||
uncached_path == kNewIncognitoTabCSSPath) {
// We generated and cached this when we initialized the object. We don't
// have to go back to the UI thread to send the data.
return NULL;
}
// If it's not a themeable image, we don't need to go to the UI thread.
int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path);
if (!BrowserThemePack::IsPersistentImageID(resource_id))
return NULL;
return content::URLDataSource::MessageLoopForRequestPath(path);
}
bool ThemeSource::ShouldReplaceExistingSource() const {
// We currently get the css_bytes_ in the ThemeSource constructor, so we need
// to recreate the source itself when a theme changes.
return true;
}
bool ThemeSource::ShouldServiceRequest(const net::URLRequest* request) const {
if (request->url().SchemeIs(chrome::kChromeSearchScheme))
return InstantIOContext::ShouldServiceRequest(request);
return URLDataSource::ShouldServiceRequest(request);
}
////////////////////////////////////////////////////////////////////////////////
// ThemeSource, private:
void ThemeSource::SendThemeBitmap(
const content::URLDataSource::GotDataCallback& callback,
int resource_id,
float scale_factor) {
ui::ScaleFactor resource_scale_factor =
ui::GetSupportedScaleFactor(scale_factor);
if (BrowserThemePack::IsPersistentImageID(resource_id)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
DCHECK(tp);
scoped_refptr<base::RefCountedMemory> image_data(
tp->GetRawData(resource_id, resource_scale_factor));
callback.Run(image_data.get());
} else {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
callback.Run(
rb.LoadDataResourceBytesForScale(resource_id, resource_scale_factor));
}
}
void ThemeSource::SendThemeImage(
const content::URLDataSource::GotDataCallback& callback,
int resource_id,
float scale_factor) {
// If the resource bundle contains the data pack for |scale_factor|, we can
// safely fallback to SendThemeBitmap().
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
if (ui::GetScaleForScaleFactor(rb.GetMaxScaleFactor()) >= scale_factor) {
SendThemeBitmap(callback, resource_id, scale_factor);
return;
}
// Otherwise, we should use gfx::ImageSkia to obtain the data. ImageSkia can
// rescale the bitmap if its backend doesn't contain the representation for
// the specified scale factor. This is the fallback path in case chrome is
// shipped without 2x resource pack but needs to use HighDPI display, which
// can happen in ChromeOS.
// TODO(mukai): remove this method itself when we ship 2x resource to all
// ChromeOS devices.
gfx::ImageSkia image;
if (BrowserThemePack::IsPersistentImageID(resource_id)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
DCHECK(tp);
image = *tp->GetImageSkiaNamed(resource_id);
} else {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
image = *rb.GetImageSkiaNamed(resource_id);
}
const gfx::ImageSkiaRep& rep = image.GetRepresentation(scale_factor);
scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes());
gfx::PNGCodec::EncodeBGRASkBitmap(
rep.sk_bitmap(), false /* discard transparency */, &data->data());
callback.Run(data.get());
}
|